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