Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/werkzeug/wrappers/request.py: 42%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

185 statements  

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 )