flask/src/flask/wrappers.py

172 lines
5.5 KiB
Python
Raw Normal View History

import typing as t
from werkzeug.exceptions import BadRequest
from werkzeug.wrappers import Request as RequestBase
from werkzeug.wrappers import Response as ResponseBase
2010-07-02 15:10:32 -04:00
from . import json
from .globals import current_app
2021-05-20 10:32:28 -07:00
from .helpers import _split_blueprint_path
2010-07-02 15:10:32 -04:00
if t.TYPE_CHECKING:
from werkzeug.routing import Rule
2013-06-12 16:27:48 +01:00
2021-01-29 10:35:37 -08:00
class Request(RequestBase):
2010-08-03 00:18:19 +08:00
"""The request object used by default in Flask. Remembers the
matched endpoint and view arguments.
It is what ends up as :class:`~flask.request`. If you want to replace
the request object used you can subclass this and set
:attr:`~flask.Flask.request_class` to your subclass.
The request object is a :class:`~werkzeug.wrappers.Request` subclass and
provides all of the attributes Werkzeug defines plus a few Flask
specific ones.
"""
2021-01-29 10:35:37 -08:00
json_module = json
2014-03-15 14:45:37 +01:00
#: The internal URL rule that matched the request. This can be
2010-07-12 23:04:24 +02:00
#: useful to inspect which methods are allowed for the URL from
#: a before/after handler (``request.url_rule.methods``) etc.
#: Though if the request's method was invalid for the URL rule,
#: the valid list is available in ``routing_exception.valid_methods``
2019-05-31 14:53:26 -04:00
#: instead (an attribute of the Werkzeug exception
#: :exc:`~werkzeug.exceptions.MethodNotAllowed`)
#: because the request was never internally bound.
2010-07-12 23:04:24 +02:00
#:
#: .. versionadded:: 0.6
url_rule: t.Optional["Rule"] = None
2014-03-15 14:45:37 +01:00
#: A dict of view arguments that matched the request. If an exception
2014-11-05 06:04:58 +03:00
#: happened when matching, this will be ``None``.
view_args: t.Optional[t.Dict[str, t.Any]] = None
2014-03-15 14:45:37 +01:00
#: If matching the URL failed, this is the exception that will be
#: raised / was raised as part of the request handling. This is
#: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
#: something similar.
routing_exception: t.Optional[Exception] = None
2010-07-14 10:47:57 +02:00
@property
def max_content_length(self) -> t.Optional[int]: # type: ignore
"""Read-only view of the ``MAX_CONTENT_LENGTH`` config key."""
2017-06-04 11:44:00 -07:00
if current_app:
return current_app.config["MAX_CONTENT_LENGTH"]
else:
return None
2010-07-14 10:47:57 +02:00
2010-07-12 23:04:24 +02:00
@property
def endpoint(self) -> t.Optional[str]:
2021-05-20 10:32:28 -07:00
"""The endpoint that matched the request URL.
This will be ``None`` if matching failed or has not been
performed yet.
This in combination with :attr:`view_args` can be used to
reconstruct the same URL or a modified URL.
2010-07-12 23:04:24 +02:00
"""
if self.url_rule is not None:
return self.url_rule.endpoint
2021-05-20 10:32:28 -07:00
return None
2010-07-12 23:04:24 +02:00
@property
def blueprint(self) -> t.Optional[str]:
2021-05-20 10:32:28 -07:00
"""The registered name of the current blueprint.
2021-05-20 10:32:28 -07:00
This will be ``None`` if the endpoint is not part of a
blueprint, or if URL matching failed or has not been performed
yet.
This does not necessarily match the name the blueprint was
created with. It may have been nested, or registered with a
different name.
"""
2021-05-20 10:32:28 -07:00
endpoint = self.endpoint
if endpoint is not None and "." in endpoint:
return endpoint.rpartition(".")[0]
return None
2021-05-20 10:32:28 -07:00
@property
def blueprints(self) -> t.List[str]:
"""The registered names of the current blueprint upwards through
parent blueprints.
2021-05-20 10:32:28 -07:00
This will be an empty list if there is no current blueprint, or
if URL matching failed.
.. versionadded:: 2.0.1
"""
name = self.blueprint
if name is None:
return []
2021-05-20 10:32:28 -07:00
return _split_blueprint_path(name)
def _load_form_data(self) -> None:
super()._load_form_data()
2014-03-15 14:45:37 +01:00
# In debug mode we're replacing the files multidict with an ad-hoc
# subclass that raises a different error for key errors.
2017-06-04 11:44:00 -07:00
if (
current_app
and current_app.debug
and self.mimetype != "multipart/form-data"
2017-06-04 11:44:00 -07:00
and not self.files
):
from .debughelpers import attach_enctype_error_multidict
2011-08-05 21:54:12 +02:00
attach_enctype_error_multidict(self)
def on_json_loading_failed(self, e: ValueError) -> t.Any:
try:
return super().on_json_loading_failed(e)
except BadRequest as e:
if current_app and current_app.debug:
raise
raise BadRequest() from e
2021-01-29 10:35:37 -08:00
class Response(ResponseBase):
2010-08-03 00:18:19 +08:00
"""The response object that is used by default in Flask. Works like the
response object from Werkzeug but is set to have an HTML mimetype by
default. Quite often you don't have to create this object yourself because
:meth:`~flask.Flask.make_response` will take care of that for you.
If you want to replace the response object used you can subclass this and
set :attr:`~flask.Flask.response_class` to your subclass.
2017-06-04 11:44:00 -07:00
.. versionchanged:: 1.0
JSON support is added to the response, like the request. This is useful
when testing to get the test client response data as JSON.
2017-04-19 05:08:53 -07:00
.. versionchanged:: 1.0
Added :attr:`max_cookie_size`.
"""
2017-06-04 11:44:00 -07:00
default_mimetype = "text/html"
2017-06-04 11:44:00 -07:00
2021-01-29 10:35:37 -08:00
json_module = json
2017-04-19 05:08:53 -07:00
2022-03-25 11:48:26 -07:00
autocorrect_location_header = False
2017-04-19 05:08:53 -07:00
@property
def max_cookie_size(self) -> int: # type: ignore
2017-04-19 05:08:53 -07:00
"""Read-only view of the :data:`MAX_COOKIE_SIZE` config key.
2021-01-29 10:38:40 -08:00
See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in
2017-04-19 05:08:53 -07:00
Werkzeug's docs.
"""
if current_app:
return current_app.config["MAX_COOKIE_SIZE"]
2017-04-19 05:08:53 -07:00
# return Werkzeug's default when not in an app context
2020-04-04 09:43:06 -07:00
return super().max_cookie_size