1from __future__ import annotations 
    2 
    3import collections.abc as cabc 
    4import functools 
    5import json 
    6import typing as t 
    7from io import BytesIO 
    8 
    9from .._internal import _wsgi_decoding_dance 
    10from ..datastructures import CombinedMultiDict 
    11from ..datastructures import EnvironHeaders 
    12from ..datastructures import FileStorage 
    13from ..datastructures import ImmutableMultiDict 
    14from ..datastructures import iter_multi_items 
    15from ..datastructures import MultiDict 
    16from ..exceptions import BadRequest 
    17from ..exceptions import UnsupportedMediaType 
    18from ..formparser import default_stream_factory 
    19from ..formparser import FormDataParser 
    20from ..sansio.request import Request as _SansIORequest 
    21from ..utils import cached_property 
    22from ..utils import environ_property 
    23from ..wsgi import _get_server 
    24from ..wsgi import get_input_stream 
    25 
    26if t.TYPE_CHECKING: 
    27    from _typeshed.wsgi import WSGIApplication 
    28    from _typeshed.wsgi import WSGIEnvironment 
    29 
    30 
    31class Request(_SansIORequest): 
    32    """Represents an incoming WSGI HTTP request, with headers and body 
    33    taken from the WSGI environment. Has properties and methods for 
    34    using the functionality defined by various HTTP specs. The data in 
    35    requests object is read-only. 
    36 
    37    Text data is assumed to use UTF-8 encoding, which should be true for 
    38    the vast majority of modern clients. Using an encoding set by the 
    39    client is unsafe in Python due to extra encodings it provides, such 
    40    as ``zip``. To change the assumed encoding, subclass and replace 
    41    :attr:`charset`. 
    42 
    43    :param environ: The WSGI environ is generated by the WSGI server and 
    44        contains information about the server configuration and client 
    45        request. 
    46    :param populate_request: Add this request object to the WSGI environ 
    47        as ``environ['werkzeug.request']``. Can be useful when 
    48        debugging. 
    49    :param shallow: Makes reading from :attr:`stream` (and any method 
    50        that would read from it) raise a :exc:`RuntimeError`. Useful to 
    51        prevent consuming the form data in middleware, which would make 
    52        it unavailable to the final application. 
    53 
    54    .. versionchanged:: 3.0 
    55        The ``charset``, ``url_charset``, and ``encoding_errors`` parameters 
    56        were removed. 
    57 
    58    .. versionchanged:: 2.1 
    59        Old ``BaseRequest`` and mixin classes were removed. 
    60 
    61    .. versionchanged:: 2.1 
    62        Remove the ``disable_data_descriptor`` attribute. 
    63 
    64    .. versionchanged:: 2.0 
    65        Combine ``BaseRequest`` and mixins into a single ``Request`` 
    66        class. 
    67 
    68    .. versionchanged:: 0.5 
    69        Read-only mode is enforced with immutable classes for all data. 
    70    """ 
    71 
    72    #: the maximum content length.  This is forwarded to the form data 
    73    #: parsing function (:func:`parse_form_data`).  When set and the 
    74    #: :attr:`form` or :attr:`files` attribute is accessed and the 
    75    #: parsing fails because more than the specified value is transmitted 
    76    #: a :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. 
    77    #: 
    78    #: .. versionadded:: 0.5 
    79    max_content_length: int | None = None 
    80 
    81    #: the maximum form field size.  This is forwarded to the form data 
    82    #: parsing function (:func:`parse_form_data`).  When set and the 
    83    #: :attr:`form` or :attr:`files` attribute is accessed and the 
    84    #: data in memory for post data is longer than the specified value a 
    85    #: :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. 
    86    #: 
    87    #: .. versionchanged:: 3.1 
    88    #:     Defaults to 500kB instead of unlimited. 
    89    #: 
    90    #: .. versionadded:: 0.5 
    91    max_form_memory_size: int | None = 500_000 
    92 
    93    #: The maximum number of multipart parts to parse, passed to 
    94    #: :attr:`form_data_parser_class`. Parsing form data with more than this 
    95    #: many parts will raise :exc:`~.RequestEntityTooLarge`. 
    96    #: 
    97    #: .. versionadded:: 2.2.3 
    98    max_form_parts = 1000 
    99 
    100    #: The form data parser that should be used.  Can be replaced to customize 
    101    #: the form date parsing. 
    102    form_data_parser_class: type[FormDataParser] = FormDataParser 
    103 
    104    #: The WSGI environment containing HTTP headers and information from 
    105    #: the WSGI server. 
    106    environ: WSGIEnvironment 
    107 
    108    #: Set when creating the request object. If ``True``, reading from 
    109    #: the request body will cause a ``RuntimeException``. Useful to 
    110    #: prevent modifying the stream from middleware. 
    111    shallow: bool 
    112 
    113    def __init__( 
    114        self, 
    115        environ: WSGIEnvironment, 
    116        populate_request: bool = True, 
    117        shallow: bool = False, 
    118    ) -> None: 
    119        super().__init__( 
    120            method=environ.get("REQUEST_METHOD", "GET"), 
    121            scheme=environ.get("wsgi.url_scheme", "http"), 
    122            server=_get_server(environ), 
    123            root_path=_wsgi_decoding_dance(environ.get("SCRIPT_NAME") or ""), 
    124            path=_wsgi_decoding_dance(environ.get("PATH_INFO") or ""), 
    125            query_string=environ.get("QUERY_STRING", "").encode("latin1"), 
    126            headers=EnvironHeaders(environ), 
    127            remote_addr=environ.get("REMOTE_ADDR"), 
    128        ) 
    129        self.environ = environ 
    130        self.shallow = shallow 
    131 
    132        if populate_request and not shallow: 
    133            self.environ["werkzeug.request"] = self 
    134 
    135    @classmethod 
    136    def from_values(cls, *args: t.Any, **kwargs: t.Any) -> Request: 
    137        """Create a new request object based on the values provided.  If 
    138        environ is given missing values are filled from there.  This method is 
    139        useful for small scripts when you need to simulate a request from an URL. 
    140        Do not use this method for unittesting, there is a full featured client 
    141        object (:class:`Client`) that allows to create multipart requests, 
    142        support for cookies etc. 
    143 
    144        This accepts the same options as the 
    145        :class:`~werkzeug.test.EnvironBuilder`. 
    146 
    147        .. versionchanged:: 0.5 
    148           This method now accepts the same arguments as 
    149           :class:`~werkzeug.test.EnvironBuilder`.  Because of this the 
    150           `environ` parameter is now called `environ_overrides`. 
    151 
    152        :return: request object 
    153        """ 
    154        from ..test import EnvironBuilder 
    155 
    156        builder = EnvironBuilder(*args, **kwargs) 
    157        try: 
    158            return builder.get_request(cls) 
    159        finally: 
    160            builder.close() 
    161 
    162    @classmethod 
    163    def application(cls, f: t.Callable[[Request], WSGIApplication]) -> WSGIApplication: 
    164        """Decorate a function as responder that accepts the request as 
    165        the last argument.  This works like the :func:`responder` 
    166        decorator but the function is passed the request object as the 
    167        last argument and the request object will be closed 
    168        automatically:: 
    169 
    170            @Request.application 
    171            def my_wsgi_app(request): 
    172                return Response('Hello World!') 
    173 
    174        As of Werkzeug 0.14 HTTP exceptions are automatically caught and 
    175        converted to responses instead of failing. 
    176 
    177        :param f: the WSGI callable to decorate 
    178        :return: a new WSGI callable 
    179        """ 
    180        #: return a callable that wraps the -2nd argument with the request 
    181        #: and calls the function with all the arguments up to that one and 
    182        #: the request.  The return value is then called with the latest 
    183        #: two arguments.  This makes it possible to use this decorator for 
    184        #: both standalone WSGI functions as well as bound methods and 
    185        #: partially applied functions. 
    186        from ..exceptions import HTTPException 
    187 
    188        @functools.wraps(f) 
    189        def application(*args: t.Any) -> cabc.Iterable[bytes]: 
    190            request = cls(args[-2]) 
    191            with request: 
    192                try: 
    193                    resp = f(*args[:-2] + (request,)) 
    194                except HTTPException as e: 
    195                    resp = t.cast("WSGIApplication", e.get_response(args[-2])) 
    196                return resp(*args[-2:]) 
    197 
    198        return t.cast("WSGIApplication", application) 
    199 
    200    def _get_file_stream( 
    201        self, 
    202        total_content_length: int | None, 
    203        content_type: str | None, 
    204        filename: str | None = None, 
    205        content_length: int | None = None, 
    206    ) -> t.IO[bytes]: 
    207        """Called to get a stream for the file upload. 
    208 
    209        This must provide a file-like class with `read()`, `readline()` 
    210        and `seek()` methods that is both writeable and readable. 
    211 
    212        The default implementation returns a temporary file if the total 
    213        content length is higher than 500KB.  Because many browsers do not 
    214        provide a content length for the files only the total content 
    215        length matters. 
    216 
    217        :param total_content_length: the total content length of all the 
    218                                     data in the request combined.  This value 
    219                                     is guaranteed to be there. 
    220        :param content_type: the mimetype of the uploaded file. 
    221        :param filename: the filename of the uploaded file.  May be `None`. 
    222        :param content_length: the length of this file.  This value is usually 
    223                               not provided because webbrowsers do not provide 
    224                               this value. 
    225        """ 
    226        return default_stream_factory( 
    227            total_content_length=total_content_length, 
    228            filename=filename, 
    229            content_type=content_type, 
    230            content_length=content_length, 
    231        ) 
    232 
    233    @property 
    234    def want_form_data_parsed(self) -> bool: 
    235        """``True`` if the request method carries content. By default 
    236        this is true if a ``Content-Type`` is sent. 
    237 
    238        .. versionadded:: 0.8 
    239        """ 
    240        return bool(self.environ.get("CONTENT_TYPE")) 
    241 
    242    def make_form_data_parser(self) -> FormDataParser: 
    243        """Creates the form data parser. Instantiates the 
    244        :attr:`form_data_parser_class` with some parameters. 
    245 
    246        .. versionadded:: 0.8 
    247        """ 
    248        return self.form_data_parser_class( 
    249            stream_factory=self._get_file_stream, 
    250            max_form_memory_size=self.max_form_memory_size, 
    251            max_content_length=self.max_content_length, 
    252            max_form_parts=self.max_form_parts, 
    253            cls=self.parameter_storage_class, 
    254        ) 
    255 
    256    def _load_form_data(self) -> None: 
    257        """Method used internally to retrieve submitted data.  After calling 
    258        this sets `form` and `files` on the request object to multi dicts 
    259        filled with the incoming form data.  As a matter of fact the input 
    260        stream will be empty afterwards.  You can also call this method to 
    261        force the parsing of the form data. 
    262 
    263        .. versionadded:: 0.8 
    264        """ 
    265        # abort early if we have already consumed the stream 
    266        if "form" in self.__dict__: 
    267            return 
    268 
    269        if self.want_form_data_parsed: 
    270            parser = self.make_form_data_parser() 
    271            data = parser.parse( 
    272                self._get_stream_for_parsing(), 
    273                self.mimetype, 
    274                self.content_length, 
    275                self.mimetype_params, 
    276            ) 
    277        else: 
    278            data = ( 
    279                self.stream, 
    280                self.parameter_storage_class(), 
    281                self.parameter_storage_class(), 
    282            ) 
    283 
    284        # inject the values into the instance dict so that we bypass 
    285        # our cached_property non-data descriptor. 
    286        d = self.__dict__ 
    287        d["stream"], d["form"], d["files"] = data 
    288 
    289    def _get_stream_for_parsing(self) -> t.IO[bytes]: 
    290        """This is the same as accessing :attr:`stream` with the difference 
    291        that if it finds cached data from calling :meth:`get_data` first it 
    292        will create a new stream out of the cached data. 
    293 
    294        .. versionadded:: 0.9.3 
    295        """ 
    296        cached_data = getattr(self, "_cached_data", None) 
    297        if cached_data is not None: 
    298            return BytesIO(cached_data) 
    299        return self.stream 
    300 
    301    def close(self) -> None: 
    302        """Closes associated resources of this request object.  This 
    303        closes all file handles explicitly.  You can also use the request 
    304        object in a with statement which will automatically close it. 
    305 
    306        .. versionadded:: 0.9 
    307        """ 
    308        files = self.__dict__.get("files") 
    309        for _key, value in iter_multi_items(files or ()): 
    310            value.close() 
    311 
    312    def __enter__(self) -> Request: 
    313        return self 
    314 
    315    def __exit__(self, exc_type, exc_value, tb) -> None:  # type: ignore 
    316        self.close() 
    317 
    318    @cached_property 
    319    def stream(self) -> t.IO[bytes]: 
    320        """The WSGI input stream, with safety checks. This stream can only be consumed 
    321        once. 
    322 
    323        Use :meth:`get_data` to get the full data as bytes or text. The :attr:`data` 
    324        attribute will contain the full bytes only if they do not represent form data. 
    325        The :attr:`form` attribute will contain the parsed form data in that case. 
    326 
    327        Unlike :attr:`input_stream`, this stream guards against infinite streams or 
    328        reading past :attr:`content_length` or :attr:`max_content_length`. 
    329 
    330        If ``max_content_length`` is set, it can be enforced on streams if 
    331        ``wsgi.input_terminated`` is set. Otherwise, an empty stream is returned. 
    332 
    333        If the limit is reached before the underlying stream is exhausted (such as a 
    334        file that is too large, or an infinite stream), the remaining contents of the 
    335        stream cannot be read safely. Depending on how the server handles this, clients 
    336        may show a "connection reset" failure instead of seeing the 413 response. 
    337 
    338        .. versionchanged:: 2.3 
    339            Check ``max_content_length`` preemptively and while reading. 
    340 
    341        .. versionchanged:: 0.9 
    342            The stream is always set (but may be consumed) even if form parsing was 
    343            accessed first. 
    344        """ 
    345        if self.shallow: 
    346            raise RuntimeError( 
    347                "This request was created with 'shallow=True', reading" 
    348                " from the input stream is disabled." 
    349            ) 
    350 
    351        return get_input_stream( 
    352            self.environ, max_content_length=self.max_content_length 
    353        ) 
    354 
    355    input_stream = environ_property[t.IO[bytes]]( 
    356        "wsgi.input", 
    357        doc="""The raw WSGI input stream, without any safety checks. 
    358 
    359        This is dangerous to use. It does not guard against infinite streams or reading 
    360        past :attr:`content_length` or :attr:`max_content_length`. 
    361 
    362        Use :attr:`stream` instead. 
    363        """, 
    364    ) 
    365 
    366    @cached_property 
    367    def data(self) -> bytes: 
    368        """The raw data read from :attr:`stream`. Will be empty if the request 
    369        represents form data. 
    370 
    371        To get the raw data even if it represents form data, use :meth:`get_data`. 
    372        """ 
    373        return self.get_data(parse_form_data=True) 
    374 
    375    @t.overload 
    376    def get_data( 
    377        self, 
    378        cache: bool = True, 
    379        as_text: t.Literal[False] = False, 
    380        parse_form_data: bool = False, 
    381    ) -> bytes: ... 
    382 
    383    @t.overload 
    384    def get_data( 
    385        self, 
    386        cache: bool = True, 
    387        as_text: t.Literal[True] = ..., 
    388        parse_form_data: bool = False, 
    389    ) -> str: ... 
    390 
    391    def get_data( 
    392        self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False 
    393    ) -> bytes | str: 
    394        """This reads the buffered incoming data from the client into one 
    395        bytes object.  By default this is cached but that behavior can be 
    396        changed by setting `cache` to `False`. 
    397 
    398        Usually it's a bad idea to call this method without checking the 
    399        content length first as a client could send dozens of megabytes or more 
    400        to cause memory problems on the server. 
    401 
    402        Note that if the form data was already parsed this method will not 
    403        return anything as form data parsing does not cache the data like 
    404        this method does.  To implicitly invoke form data parsing function 
    405        set `parse_form_data` to `True`.  When this is done the return value 
    406        of this method will be an empty string if the form parser handles 
    407        the data.  This generally is not necessary as if the whole data is 
    408        cached (which is the default) the form parser will used the cached 
    409        data to parse the form data.  Please be generally aware of checking 
    410        the content length first in any case before calling this method 
    411        to avoid exhausting server memory. 
    412 
    413        If `as_text` is set to `True` the return value will be a decoded 
    414        string. 
    415 
    416        .. versionadded:: 0.9 
    417        """ 
    418        rv = getattr(self, "_cached_data", None) 
    419        if rv is None: 
    420            if parse_form_data: 
    421                self._load_form_data() 
    422            rv = self.stream.read() 
    423            if cache: 
    424                self._cached_data = rv 
    425        if as_text: 
    426            rv = rv.decode(errors="replace") 
    427        return rv 
    428 
    429    @cached_property 
    430    def form(self) -> ImmutableMultiDict[str, str]: 
    431        """The form parameters.  By default an 
    432        :class:`~werkzeug.datastructures.ImmutableMultiDict` 
    433        is returned from this function.  This can be changed by setting 
    434        :attr:`parameter_storage_class` to a different type.  This might 
    435        be necessary if the order of the form data is important. 
    436 
    437        Please keep in mind that file uploads will not end up here, but instead 
    438        in the :attr:`files` attribute. 
    439 
    440        .. versionchanged:: 0.9 
    441 
    442            Previous to Werkzeug 0.9 this would only contain form data for POST 
    443            and PUT requests. 
    444        """ 
    445        self._load_form_data() 
    446        return self.form 
    447 
    448    @cached_property 
    449    def values(self) -> CombinedMultiDict[str, str]: 
    450        """A :class:`werkzeug.datastructures.CombinedMultiDict` that 
    451        combines :attr:`args` and :attr:`form`. 
    452 
    453        For GET requests, only ``args`` are present, not ``form``. 
    454 
    455        .. versionchanged:: 2.0 
    456            For GET requests, only ``args`` are present, not ``form``. 
    457        """ 
    458        sources = [self.args] 
    459 
    460        if self.method != "GET": 
    461            # GET requests can have a body, and some caching proxies 
    462            # might not treat that differently than a normal GET 
    463            # request, allowing form data to "invisibly" affect the 
    464            # cache without indication in the query string / URL. 
    465            sources.append(self.form) 
    466 
    467        args = [] 
    468 
    469        for d in sources: 
    470            if not isinstance(d, MultiDict): 
    471                d = MultiDict(d) 
    472 
    473            args.append(d) 
    474 
    475        return CombinedMultiDict(args) 
    476 
    477    @cached_property 
    478    def files(self) -> ImmutableMultiDict[str, FileStorage]: 
    479        """:class:`~werkzeug.datastructures.MultiDict` object containing 
    480        all uploaded files.  Each key in :attr:`files` is the name from the 
    481        ``<input type="file" name="">``.  Each value in :attr:`files` is a 
    482        Werkzeug :class:`~werkzeug.datastructures.FileStorage` object. 
    483 
    484        It basically behaves like a standard file object you know from Python, 
    485        with the difference that it also has a 
    486        :meth:`~werkzeug.datastructures.FileStorage.save` function that can 
    487        store the file on the filesystem. 
    488 
    489        Note that :attr:`files` will only contain data if the request method was 
    490        POST, PUT or PATCH and the ``<form>`` that posted to the request had 
    491        ``enctype="multipart/form-data"``.  It will be empty otherwise. 
    492 
    493        See the :class:`~werkzeug.datastructures.MultiDict` / 
    494        :class:`~werkzeug.datastructures.FileStorage` documentation for 
    495        more details about the used data structure. 
    496        """ 
    497        self._load_form_data() 
    498        return self.files 
    499 
    500    @property 
    501    def script_root(self) -> str: 
    502        """Alias for :attr:`self.root_path`. ``environ["SCRIPT_ROOT"]`` 
    503        without a trailing slash. 
    504        """ 
    505        return self.root_path 
    506 
    507    @cached_property 
    508    def url_root(self) -> str: 
    509        """Alias for :attr:`root_url`. The URL with scheme, host, and 
    510        root path. For example, ``https://example.com/app/``. 
    511        """ 
    512        return self.root_url 
    513 
    514    remote_user = environ_property[str]( 
    515        "REMOTE_USER", 
    516        doc="""If the server supports user authentication, and the 
    517        script is protected, this attribute contains the username the 
    518        user has authenticated as.""", 
    519    ) 
    520    is_multithread = environ_property[bool]( 
    521        "wsgi.multithread", 
    522        doc="""boolean that is `True` if the application is served by a 
    523        multithreaded WSGI server.""", 
    524    ) 
    525    is_multiprocess = environ_property[bool]( 
    526        "wsgi.multiprocess", 
    527        doc="""boolean that is `True` if the application is served by a 
    528        WSGI server that spawns multiple processes.""", 
    529    ) 
    530    is_run_once = environ_property[bool]( 
    531        "wsgi.run_once", 
    532        doc="""boolean that is `True` if the application will be 
    533        executed only once in a process lifetime.  This is the case for 
    534        CGI for example, but it's not guaranteed that the execution only 
    535        happens one time.""", 
    536    ) 
    537 
    538    # JSON 
    539 
    540    #: A module or other object that has ``dumps`` and ``loads`` 
    541    #: functions that match the API of the built-in :mod:`json` module. 
    542    json_module = json 
    543 
    544    @property 
    545    def json(self) -> t.Any | None: 
    546        """The parsed JSON data if :attr:`mimetype` indicates JSON 
    547        (:mimetype:`application/json`, see :attr:`is_json`). 
    548 
    549        Calls :meth:`get_json` with default arguments. 
    550 
    551        If the request content type is not ``application/json``, this 
    552        will raise a 415 Unsupported Media Type error. 
    553 
    554        .. versionchanged:: 2.3 
    555            Raise a 415 error instead of 400. 
    556 
    557        .. versionchanged:: 2.1 
    558            Raise a 400 error if the content type is incorrect. 
    559        """ 
    560        return self.get_json() 
    561 
    562    # Cached values for ``(silent=False, silent=True)``. Initialized 
    563    # with sentinel values. 
    564    _cached_json: tuple[t.Any, t.Any] = (Ellipsis, Ellipsis) 
    565 
    566    @t.overload 
    567    def get_json( 
    568        self, force: bool = ..., silent: t.Literal[False] = ..., cache: bool = ... 
    569    ) -> t.Any: ... 
    570 
    571    @t.overload 
    572    def get_json( 
    573        self, force: bool = ..., silent: bool = ..., cache: bool = ... 
    574    ) -> t.Any | None: ... 
    575 
    576    def get_json( 
    577        self, force: bool = False, silent: bool = False, cache: bool = True 
    578    ) -> t.Any | None: 
    579        """Parse :attr:`data` as JSON. 
    580 
    581        If the mimetype does not indicate JSON 
    582        (:mimetype:`application/json`, see :attr:`is_json`), or parsing 
    583        fails, :meth:`on_json_loading_failed` is called and 
    584        its return value is used as the return value. By default this 
    585        raises a 415 Unsupported Media Type resp. 
    586 
    587        :param force: Ignore the mimetype and always try to parse JSON. 
    588        :param silent: Silence mimetype and parsing errors, and 
    589            return ``None`` instead. 
    590        :param cache: Store the parsed JSON to return for subsequent 
    591            calls. 
    592 
    593        .. versionchanged:: 2.3 
    594            Raise a 415 error instead of 400. 
    595 
    596        .. versionchanged:: 2.1 
    597            Raise a 400 error if the content type is incorrect. 
    598        """ 
    599        if cache and self._cached_json[silent] is not Ellipsis: 
    600            return self._cached_json[silent] 
    601 
    602        if not (force or self.is_json): 
    603            if not silent: 
    604                return self.on_json_loading_failed(None) 
    605            else: 
    606                return None 
    607 
    608        data = self.get_data(cache=cache) 
    609 
    610        try: 
    611            rv = self.json_module.loads(data) 
    612        except ValueError as e: 
    613            if silent: 
    614                rv = None 
    615 
    616                if cache: 
    617                    normal_rv, _ = self._cached_json 
    618                    self._cached_json = (normal_rv, rv) 
    619            else: 
    620                rv = self.on_json_loading_failed(e) 
    621 
    622                if cache: 
    623                    _, silent_rv = self._cached_json 
    624                    self._cached_json = (rv, silent_rv) 
    625        else: 
    626            if cache: 
    627                self._cached_json = (rv, rv) 
    628 
    629        return rv 
    630 
    631    def on_json_loading_failed(self, e: ValueError | None) -> t.Any: 
    632        """Called if :meth:`get_json` fails and isn't silenced. 
    633 
    634        If this method returns a value, it is used as the return value 
    635        for :meth:`get_json`. The default implementation raises 
    636        :exc:`~werkzeug.exceptions.BadRequest`. 
    637 
    638        :param e: If parsing failed, this is the exception. It will be 
    639            ``None`` if the content type wasn't ``application/json``. 
    640 
    641        .. versionchanged:: 2.3 
    642            Raise a 415 error instead of 400. 
    643        """ 
    644        if e is not None: 
    645            raise BadRequest(f"Failed to decode JSON object: {e}") 
    646 
    647        raise UnsupportedMediaType( 
    648            "Did not attempt to load JSON data because the request" 
    649            " Content-Type was not 'application/json'." 
    650        )