Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/werkzeug/wrappers/request.py: 41%
174 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +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 form data parser that should be used. Can be replaced to customize
87 #: the form date parsing.
88 form_data_parser_class: t.Type[FormDataParser] = FormDataParser
90 #: The WSGI environment containing HTTP headers and information from
91 #: the WSGI server.
92 environ: "WSGIEnvironment"
94 #: Set when creating the request object. If ``True``, reading from
95 #: the request body will cause a ``RuntimeException``. Useful to
96 #: prevent modifying the stream from middleware.
97 shallow: bool
99 def __init__(
100 self,
101 environ: "WSGIEnvironment",
102 populate_request: bool = True,
103 shallow: bool = False,
104 ) -> None:
105 super().__init__(
106 method=environ.get("REQUEST_METHOD", "GET"),
107 scheme=environ.get("wsgi.url_scheme", "http"),
108 server=_get_server(environ),
109 root_path=_wsgi_decoding_dance(
110 environ.get("SCRIPT_NAME") or "", self.charset, self.encoding_errors
111 ),
112 path=_wsgi_decoding_dance(
113 environ.get("PATH_INFO") or "", self.charset, self.encoding_errors
114 ),
115 query_string=environ.get("QUERY_STRING", "").encode("latin1"),
116 headers=EnvironHeaders(environ),
117 remote_addr=environ.get("REMOTE_ADDR"),
118 )
119 self.environ = environ
120 self.shallow = shallow
122 if populate_request and not shallow:
123 self.environ["werkzeug.request"] = self
125 @classmethod
126 def from_values(cls, *args: t.Any, **kwargs: t.Any) -> "Request":
127 """Create a new request object based on the values provided. If
128 environ is given missing values are filled from there. This method is
129 useful for small scripts when you need to simulate a request from an URL.
130 Do not use this method for unittesting, there is a full featured client
131 object (:class:`Client`) that allows to create multipart requests,
132 support for cookies etc.
134 This accepts the same options as the
135 :class:`~werkzeug.test.EnvironBuilder`.
137 .. versionchanged:: 0.5
138 This method now accepts the same arguments as
139 :class:`~werkzeug.test.EnvironBuilder`. Because of this the
140 `environ` parameter is now called `environ_overrides`.
142 :return: request object
143 """
144 from ..test import EnvironBuilder
146 charset = kwargs.pop("charset", cls.charset)
147 kwargs["charset"] = charset
148 builder = EnvironBuilder(*args, **kwargs)
149 try:
150 return builder.get_request(cls)
151 finally:
152 builder.close()
154 @classmethod
155 def application(
156 cls, f: t.Callable[["Request"], "WSGIApplication"]
157 ) -> "WSGIApplication":
158 """Decorate a function as responder that accepts the request as
159 the last argument. This works like the :func:`responder`
160 decorator but the function is passed the request object as the
161 last argument and the request object will be closed
162 automatically::
164 @Request.application
165 def my_wsgi_app(request):
166 return Response('Hello World!')
168 As of Werkzeug 0.14 HTTP exceptions are automatically caught and
169 converted to responses instead of failing.
171 :param f: the WSGI callable to decorate
172 :return: a new WSGI callable
173 """
174 #: return a callable that wraps the -2nd argument with the request
175 #: and calls the function with all the arguments up to that one and
176 #: the request. The return value is then called with the latest
177 #: two arguments. This makes it possible to use this decorator for
178 #: both standalone WSGI functions as well as bound methods and
179 #: partially applied functions.
180 from ..exceptions import HTTPException
182 @functools.wraps(f)
183 def application(*args): # type: ignore
184 request = cls(args[-2])
185 with request:
186 try:
187 resp = f(*args[:-2] + (request,))
188 except HTTPException as e:
189 resp = e.get_response(args[-2])
190 return resp(*args[-2:])
192 return t.cast("WSGIApplication", application)
194 def _get_file_stream(
195 self,
196 total_content_length: t.Optional[int],
197 content_type: t.Optional[str],
198 filename: t.Optional[str] = None,
199 content_length: t.Optional[int] = None,
200 ) -> t.IO[bytes]:
201 """Called to get a stream for the file upload.
203 This must provide a file-like class with `read()`, `readline()`
204 and `seek()` methods that is both writeable and readable.
206 The default implementation returns a temporary file if the total
207 content length is higher than 500KB. Because many browsers do not
208 provide a content length for the files only the total content
209 length matters.
211 :param total_content_length: the total content length of all the
212 data in the request combined. This value
213 is guaranteed to be there.
214 :param content_type: the mimetype of the uploaded file.
215 :param filename: the filename of the uploaded file. May be `None`.
216 :param content_length: the length of this file. This value is usually
217 not provided because webbrowsers do not provide
218 this value.
219 """
220 return default_stream_factory(
221 total_content_length=total_content_length,
222 filename=filename,
223 content_type=content_type,
224 content_length=content_length,
225 )
227 @property
228 def want_form_data_parsed(self) -> bool:
229 """``True`` if the request method carries content. By default
230 this is true if a ``Content-Type`` is sent.
232 .. versionadded:: 0.8
233 """
234 return bool(self.environ.get("CONTENT_TYPE"))
236 def make_form_data_parser(self) -> FormDataParser:
237 """Creates the form data parser. Instantiates the
238 :attr:`form_data_parser_class` with some parameters.
240 .. versionadded:: 0.8
241 """
242 return self.form_data_parser_class(
243 self._get_file_stream,
244 self.charset,
245 self.encoding_errors,
246 self.max_form_memory_size,
247 self.max_content_length,
248 self.parameter_storage_class,
249 )
251 def _load_form_data(self) -> None:
252 """Method used internally to retrieve submitted data. After calling
253 this sets `form` and `files` on the request object to multi dicts
254 filled with the incoming form data. As a matter of fact the input
255 stream will be empty afterwards. You can also call this method to
256 force the parsing of the form data.
258 .. versionadded:: 0.8
259 """
260 # abort early if we have already consumed the stream
261 if "form" in self.__dict__:
262 return
264 if self.want_form_data_parsed:
265 parser = self.make_form_data_parser()
266 data = parser.parse(
267 self._get_stream_for_parsing(),
268 self.mimetype,
269 self.content_length,
270 self.mimetype_params,
271 )
272 else:
273 data = (
274 self.stream,
275 self.parameter_storage_class(),
276 self.parameter_storage_class(),
277 )
279 # inject the values into the instance dict so that we bypass
280 # our cached_property non-data descriptor.
281 d = self.__dict__
282 d["stream"], d["form"], d["files"] = data
284 def _get_stream_for_parsing(self) -> t.IO[bytes]:
285 """This is the same as accessing :attr:`stream` with the difference
286 that if it finds cached data from calling :meth:`get_data` first it
287 will create a new stream out of the cached data.
289 .. versionadded:: 0.9.3
290 """
291 cached_data = getattr(self, "_cached_data", None)
292 if cached_data is not None:
293 return BytesIO(cached_data)
294 return self.stream
296 def close(self) -> None:
297 """Closes associated resources of this request object. This
298 closes all file handles explicitly. You can also use the request
299 object in a with statement which will automatically close it.
301 .. versionadded:: 0.9
302 """
303 files = self.__dict__.get("files")
304 for _key, value in iter_multi_items(files or ()):
305 value.close()
307 def __enter__(self) -> "Request":
308 return self
310 def __exit__(self, exc_type, exc_value, tb) -> None: # type: ignore
311 self.close()
313 @cached_property
314 def stream(self) -> t.IO[bytes]:
315 """
316 If the incoming form data was not encoded with a known mimetype
317 the data is stored unmodified in this stream for consumption. Most
318 of the time it is a better idea to use :attr:`data` which will give
319 you that data as a string. The stream only returns the data once.
321 Unlike :attr:`input_stream` this stream is properly guarded that you
322 can't accidentally read past the length of the input. Werkzeug will
323 internally always refer to this stream to read data which makes it
324 possible to wrap this object with a stream that does filtering.
326 .. versionchanged:: 0.9
327 This stream is now always available but might be consumed by the
328 form parser later on. Previously the stream was only set if no
329 parsing happened.
330 """
331 if self.shallow:
332 raise RuntimeError(
333 "This request was created with 'shallow=True', reading"
334 " from the input stream is disabled."
335 )
337 return get_input_stream(self.environ)
339 input_stream = environ_property[t.IO[bytes]](
340 "wsgi.input",
341 doc="""The WSGI input stream.
343 In general it's a bad idea to use this one because you can
344 easily read past the boundary. Use the :attr:`stream`
345 instead.""",
346 )
348 @cached_property
349 def data(self) -> bytes:
350 """
351 Contains the incoming request data as string in case it came with
352 a mimetype Werkzeug does not handle.
353 """
354 return self.get_data(parse_form_data=True)
356 @typing.overload
357 def get_data( # type: ignore
358 self,
359 cache: bool = True,
360 as_text: "te.Literal[False]" = False,
361 parse_form_data: bool = False,
362 ) -> bytes:
363 ...
365 @typing.overload
366 def get_data(
367 self,
368 cache: bool = True,
369 as_text: "te.Literal[True]" = ...,
370 parse_form_data: bool = False,
371 ) -> str:
372 ...
374 def get_data(
375 self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False
376 ) -> t.Union[bytes, str]:
377 """This reads the buffered incoming data from the client into one
378 bytes object. By default this is cached but that behavior can be
379 changed by setting `cache` to `False`.
381 Usually it's a bad idea to call this method without checking the
382 content length first as a client could send dozens of megabytes or more
383 to cause memory problems on the server.
385 Note that if the form data was already parsed this method will not
386 return anything as form data parsing does not cache the data like
387 this method does. To implicitly invoke form data parsing function
388 set `parse_form_data` to `True`. When this is done the return value
389 of this method will be an empty string if the form parser handles
390 the data. This generally is not necessary as if the whole data is
391 cached (which is the default) the form parser will used the cached
392 data to parse the form data. Please be generally aware of checking
393 the content length first in any case before calling this method
394 to avoid exhausting server memory.
396 If `as_text` is set to `True` the return value will be a decoded
397 string.
399 .. versionadded:: 0.9
400 """
401 rv = getattr(self, "_cached_data", None)
402 if rv is None:
403 if parse_form_data:
404 self._load_form_data()
405 rv = self.stream.read()
406 if cache:
407 self._cached_data = rv
408 if as_text:
409 rv = rv.decode(self.charset, self.encoding_errors)
410 return rv
412 @cached_property
413 def form(self) -> "ImmutableMultiDict[str, str]":
414 """The form parameters. By default an
415 :class:`~werkzeug.datastructures.ImmutableMultiDict`
416 is returned from this function. This can be changed by setting
417 :attr:`parameter_storage_class` to a different type. This might
418 be necessary if the order of the form data is important.
420 Please keep in mind that file uploads will not end up here, but instead
421 in the :attr:`files` attribute.
423 .. versionchanged:: 0.9
425 Previous to Werkzeug 0.9 this would only contain form data for POST
426 and PUT requests.
427 """
428 self._load_form_data()
429 return self.form
431 @cached_property
432 def values(self) -> "CombinedMultiDict[str, str]":
433 """A :class:`werkzeug.datastructures.CombinedMultiDict` that
434 combines :attr:`args` and :attr:`form`.
436 For GET requests, only ``args`` are present, not ``form``.
438 .. versionchanged:: 2.0
439 For GET requests, only ``args`` are present, not ``form``.
440 """
441 sources = [self.args]
443 if self.method != "GET":
444 # GET requests can have a body, and some caching proxies
445 # might not treat that differently than a normal GET
446 # request, allowing form data to "invisibly" affect the
447 # cache without indication in the query string / URL.
448 sources.append(self.form)
450 args = []
452 for d in sources:
453 if not isinstance(d, MultiDict):
454 d = MultiDict(d)
456 args.append(d)
458 return CombinedMultiDict(args)
460 @cached_property
461 def files(self) -> "ImmutableMultiDict[str, FileStorage]":
462 """:class:`~werkzeug.datastructures.MultiDict` object containing
463 all uploaded files. Each key in :attr:`files` is the name from the
464 ``<input type="file" name="">``. Each value in :attr:`files` is a
465 Werkzeug :class:`~werkzeug.datastructures.FileStorage` object.
467 It basically behaves like a standard file object you know from Python,
468 with the difference that it also has a
469 :meth:`~werkzeug.datastructures.FileStorage.save` function that can
470 store the file on the filesystem.
472 Note that :attr:`files` will only contain data if the request method was
473 POST, PUT or PATCH and the ``<form>`` that posted to the request had
474 ``enctype="multipart/form-data"``. It will be empty otherwise.
476 See the :class:`~werkzeug.datastructures.MultiDict` /
477 :class:`~werkzeug.datastructures.FileStorage` documentation for
478 more details about the used data structure.
479 """
480 self._load_form_data()
481 return self.files
483 @property
484 def script_root(self) -> str:
485 """Alias for :attr:`self.root_path`. ``environ["SCRIPT_ROOT"]``
486 without a trailing slash.
487 """
488 return self.root_path
490 @cached_property
491 def url_root(self) -> str:
492 """Alias for :attr:`root_url`. The URL with scheme, host, and
493 root path. For example, ``https://example.com/app/``.
494 """
495 return self.root_url
497 remote_user = environ_property[str](
498 "REMOTE_USER",
499 doc="""If the server supports user authentication, and the
500 script is protected, this attribute contains the username the
501 user has authenticated as.""",
502 )
503 is_multithread = environ_property[bool](
504 "wsgi.multithread",
505 doc="""boolean that is `True` if the application is served by a
506 multithreaded WSGI server.""",
507 )
508 is_multiprocess = environ_property[bool](
509 "wsgi.multiprocess",
510 doc="""boolean that is `True` if the application is served by a
511 WSGI server that spawns multiple processes.""",
512 )
513 is_run_once = environ_property[bool](
514 "wsgi.run_once",
515 doc="""boolean that is `True` if the application will be
516 executed only once in a process lifetime. This is the case for
517 CGI for example, but it's not guaranteed that the execution only
518 happens one time.""",
519 )
521 # JSON
523 #: A module or other object that has ``dumps`` and ``loads``
524 #: functions that match the API of the built-in :mod:`json` module.
525 json_module = json
527 @property
528 def json(self) -> t.Optional[t.Any]:
529 """The parsed JSON data if :attr:`mimetype` indicates JSON
530 (:mimetype:`application/json`, see :attr:`is_json`).
532 Calls :meth:`get_json` with default arguments.
534 If the request content type is not ``application/json``, this
535 will raise a 400 Bad Request error.
537 .. versionchanged:: 2.1
538 Raise a 400 error if the content type is incorrect.
539 """
540 return self.get_json()
542 # Cached values for ``(silent=False, silent=True)``. Initialized
543 # with sentinel values.
544 _cached_json: t.Tuple[t.Any, t.Any] = (Ellipsis, Ellipsis)
546 def get_json(
547 self, force: bool = False, silent: bool = False, cache: bool = True
548 ) -> t.Optional[t.Any]:
549 """Parse :attr:`data` as JSON.
551 If the mimetype does not indicate JSON
552 (:mimetype:`application/json`, see :attr:`is_json`), or parsing
553 fails, :meth:`on_json_loading_failed` is called and
554 its return value is used as the return value. By default this
555 raises a 400 Bad Request error.
557 :param force: Ignore the mimetype and always try to parse JSON.
558 :param silent: Silence mimetype and parsing errors, and
559 return ``None`` instead.
560 :param cache: Store the parsed JSON to return for subsequent
561 calls.
563 .. versionchanged:: 2.1
564 Raise a 400 error if the content type is incorrect.
565 """
566 if cache and self._cached_json[silent] is not Ellipsis:
567 return self._cached_json[silent]
569 if not (force or self.is_json):
570 if not silent:
571 return self.on_json_loading_failed(None)
572 else:
573 return None
575 data = self.get_data(cache=cache)
577 try:
578 rv = self.json_module.loads(data)
579 except ValueError as e:
580 if silent:
581 rv = None
583 if cache:
584 normal_rv, _ = self._cached_json
585 self._cached_json = (normal_rv, rv)
586 else:
587 rv = self.on_json_loading_failed(e)
589 if cache:
590 _, silent_rv = self._cached_json
591 self._cached_json = (rv, silent_rv)
592 else:
593 if cache:
594 self._cached_json = (rv, rv)
596 return rv
598 def on_json_loading_failed(self, e: t.Optional[ValueError]) -> t.Any:
599 """Called if :meth:`get_json` fails and isn't silenced.
601 If this method returns a value, it is used as the return value
602 for :meth:`get_json`. The default implementation raises
603 :exc:`~werkzeug.exceptions.BadRequest`.
605 :param e: If parsing failed, this is the exception. It will be
606 ``None`` if the content type wasn't ``application/json``.
607 """
608 if e is not None:
609 raise BadRequest(f"Failed to decode JSON object: {e}")
611 raise BadRequest(
612 "Did not attempt to load JSON data because the request"
613 " Content-Type was not 'application/json'."
614 )