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