258 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Python
		
	
	
	
from __future__ import annotations
 | 
						|
 | 
						|
import typing as t
 | 
						|
 | 
						|
from werkzeug.exceptions import BadRequest
 | 
						|
from werkzeug.exceptions import HTTPException
 | 
						|
from werkzeug.wrappers import Request as RequestBase
 | 
						|
from werkzeug.wrappers import Response as ResponseBase
 | 
						|
 | 
						|
from . import json
 | 
						|
from .globals import current_app
 | 
						|
from .helpers import _split_blueprint_path
 | 
						|
 | 
						|
if t.TYPE_CHECKING:  # pragma: no cover
 | 
						|
    from werkzeug.routing import Rule
 | 
						|
 | 
						|
 | 
						|
class Request(RequestBase):
 | 
						|
    """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.
 | 
						|
    """
 | 
						|
 | 
						|
    json_module: t.Any = json
 | 
						|
 | 
						|
    #: The internal URL rule that matched the request.  This can be
 | 
						|
    #: 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``
 | 
						|
    #: instead (an attribute of the Werkzeug exception
 | 
						|
    #: :exc:`~werkzeug.exceptions.MethodNotAllowed`)
 | 
						|
    #: because the request was never internally bound.
 | 
						|
    #:
 | 
						|
    #: .. versionadded:: 0.6
 | 
						|
    url_rule: Rule | None = None
 | 
						|
 | 
						|
    #: A dict of view arguments that matched the request.  If an exception
 | 
						|
    #: happened when matching, this will be ``None``.
 | 
						|
    view_args: dict[str, t.Any] | None = None
 | 
						|
 | 
						|
    #: 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: HTTPException | None = None
 | 
						|
 | 
						|
    _max_content_length: int | None = None
 | 
						|
    _max_form_memory_size: int | None = None
 | 
						|
    _max_form_parts: int | None = None
 | 
						|
 | 
						|
    @property
 | 
						|
    def max_content_length(self) -> int | None:
 | 
						|
        """The maximum number of bytes that will be read during this request. If
 | 
						|
        this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge`
 | 
						|
        error is raised. If it is set to ``None``, no limit is enforced at the
 | 
						|
        Flask application level. However, if it is ``None`` and the request has
 | 
						|
        no ``Content-Length`` header and the WSGI server does not indicate that
 | 
						|
        it terminates the stream, then no data is read to avoid an infinite
 | 
						|
        stream.
 | 
						|
 | 
						|
        Each request defaults to the :data:`MAX_CONTENT_LENGTH` config, which
 | 
						|
        defaults to ``None``. It can be set on a specific ``request`` to apply
 | 
						|
        the limit to that specific view. This should be set appropriately based
 | 
						|
        on an application's or view's specific needs.
 | 
						|
 | 
						|
        .. versionchanged:: 3.1
 | 
						|
            This can be set per-request.
 | 
						|
 | 
						|
        .. versionchanged:: 0.6
 | 
						|
            This is configurable through Flask config.
 | 
						|
        """
 | 
						|
        if self._max_content_length is not None:
 | 
						|
            return self._max_content_length
 | 
						|
 | 
						|
        if not current_app:
 | 
						|
            return super().max_content_length
 | 
						|
 | 
						|
        return current_app.config["MAX_CONTENT_LENGTH"]  # type: ignore[no-any-return]
 | 
						|
 | 
						|
    @max_content_length.setter
 | 
						|
    def max_content_length(self, value: int | None) -> None:
 | 
						|
        self._max_content_length = value
 | 
						|
 | 
						|
    @property
 | 
						|
    def max_form_memory_size(self) -> int | None:
 | 
						|
        """The maximum size in bytes any non-file form field may be in a
 | 
						|
        ``multipart/form-data`` body. If this limit is exceeded, a 413
 | 
						|
        :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it
 | 
						|
        is set to ``None``, no limit is enforced at the Flask application level.
 | 
						|
 | 
						|
        Each request defaults to the :data:`MAX_FORM_MEMORY_SIZE` config, which
 | 
						|
        defaults to ``500_000``. It can be set on a specific ``request`` to
 | 
						|
        apply the limit to that specific view. This should be set appropriately
 | 
						|
        based on an application's or view's specific needs.
 | 
						|
 | 
						|
        .. versionchanged:: 3.1
 | 
						|
            This is configurable through Flask config.
 | 
						|
        """
 | 
						|
        if self._max_form_memory_size is not None:
 | 
						|
            return self._max_form_memory_size
 | 
						|
 | 
						|
        if not current_app:
 | 
						|
            return super().max_form_memory_size
 | 
						|
 | 
						|
        return current_app.config["MAX_FORM_MEMORY_SIZE"]  # type: ignore[no-any-return]
 | 
						|
 | 
						|
    @max_form_memory_size.setter
 | 
						|
    def max_form_memory_size(self, value: int | None) -> None:
 | 
						|
        self._max_form_memory_size = value
 | 
						|
 | 
						|
    @property  # type: ignore[override]
 | 
						|
    def max_form_parts(self) -> int | None:
 | 
						|
        """The maximum number of fields that may be present in a
 | 
						|
        ``multipart/form-data`` body. If this limit is exceeded, a 413
 | 
						|
        :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it
 | 
						|
        is set to ``None``, no limit is enforced at the Flask application level.
 | 
						|
 | 
						|
        Each request defaults to the :data:`MAX_FORM_PARTS` config, which
 | 
						|
        defaults to ``1_000``. It can be set on a specific ``request`` to apply
 | 
						|
        the limit to that specific view. This should be set appropriately based
 | 
						|
        on an application's or view's specific needs.
 | 
						|
 | 
						|
        .. versionchanged:: 3.1
 | 
						|
            This is configurable through Flask config.
 | 
						|
        """
 | 
						|
        if self._max_form_parts is not None:
 | 
						|
            return self._max_form_parts
 | 
						|
 | 
						|
        if not current_app:
 | 
						|
            return super().max_form_parts
 | 
						|
 | 
						|
        return current_app.config["MAX_FORM_PARTS"]  # type: ignore[no-any-return]
 | 
						|
 | 
						|
    @max_form_parts.setter
 | 
						|
    def max_form_parts(self, value: int | None) -> None:
 | 
						|
        self._max_form_parts = value
 | 
						|
 | 
						|
    @property
 | 
						|
    def endpoint(self) -> str | None:
 | 
						|
        """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.
 | 
						|
        """
 | 
						|
        if self.url_rule is not None:
 | 
						|
            return self.url_rule.endpoint  # type: ignore[no-any-return]
 | 
						|
 | 
						|
        return None
 | 
						|
 | 
						|
    @property
 | 
						|
    def blueprint(self) -> str | None:
 | 
						|
        """The registered name of the current blueprint.
 | 
						|
 | 
						|
        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.
 | 
						|
        """
 | 
						|
        endpoint = self.endpoint
 | 
						|
 | 
						|
        if endpoint is not None and "." in endpoint:
 | 
						|
            return endpoint.rpartition(".")[0]
 | 
						|
 | 
						|
        return None
 | 
						|
 | 
						|
    @property
 | 
						|
    def blueprints(self) -> list[str]:
 | 
						|
        """The registered names of the current blueprint upwards through
 | 
						|
        parent blueprints.
 | 
						|
 | 
						|
        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 []
 | 
						|
 | 
						|
        return _split_blueprint_path(name)
 | 
						|
 | 
						|
    def _load_form_data(self) -> None:
 | 
						|
        super()._load_form_data()
 | 
						|
 | 
						|
        # In debug mode we're replacing the files multidict with an ad-hoc
 | 
						|
        # subclass that raises a different error for key errors.
 | 
						|
        if (
 | 
						|
            current_app
 | 
						|
            and current_app.debug
 | 
						|
            and self.mimetype != "multipart/form-data"
 | 
						|
            and not self.files
 | 
						|
        ):
 | 
						|
            from .debughelpers import attach_enctype_error_multidict
 | 
						|
 | 
						|
            attach_enctype_error_multidict(self)
 | 
						|
 | 
						|
    def on_json_loading_failed(self, e: ValueError | None) -> t.Any:
 | 
						|
        try:
 | 
						|
            return super().on_json_loading_failed(e)
 | 
						|
        except BadRequest as ebr:
 | 
						|
            if current_app and current_app.debug:
 | 
						|
                raise
 | 
						|
 | 
						|
            raise BadRequest() from ebr
 | 
						|
 | 
						|
 | 
						|
class Response(ResponseBase):
 | 
						|
    """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.
 | 
						|
 | 
						|
    .. 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.
 | 
						|
 | 
						|
    .. versionchanged:: 1.0
 | 
						|
 | 
						|
        Added :attr:`max_cookie_size`.
 | 
						|
    """
 | 
						|
 | 
						|
    default_mimetype: str | None = "text/html"
 | 
						|
 | 
						|
    json_module = json
 | 
						|
 | 
						|
    autocorrect_location_header = False
 | 
						|
 | 
						|
    @property
 | 
						|
    def max_cookie_size(self) -> int:  # type: ignore
 | 
						|
        """Read-only view of the :data:`MAX_COOKIE_SIZE` config key.
 | 
						|
 | 
						|
        See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in
 | 
						|
        Werkzeug's docs.
 | 
						|
        """
 | 
						|
        if current_app:
 | 
						|
            return current_app.config["MAX_COOKIE_SIZE"]  # type: ignore[no-any-return]
 | 
						|
 | 
						|
        # return Werkzeug's default when not in an app context
 | 
						|
        return super().max_cookie_size
 |