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

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

179 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 from _typeshed.wsgi import WSGIApplication 

28 from _typeshed.wsgi import WSGIEnvironment 

29 

30 

31class Request(_SansIORequest): 

32 """Represents an incoming WSGI HTTP request, with headers and body 

33 taken from the WSGI environment. Has properties and methods for 

34 using the functionality defined by various HTTP specs. The data in 

35 requests object is read-only. 

36 

37 Text data is assumed to use UTF-8 encoding, which should be true for 

38 the vast majority of modern clients. Using an encoding set by the 

39 client is unsafe in Python due to extra encodings it provides, such 

40 as ``zip``. To change the assumed encoding, subclass and replace 

41 :attr:`charset`. 

42 

43 :param environ: The WSGI environ is generated by the WSGI server and 

44 contains information about the server configuration and client 

45 request. 

46 :param populate_request: Add this request object to the WSGI environ 

47 as ``environ['werkzeug.request']``. Can be useful when 

48 debugging. 

49 :param shallow: Makes reading from :attr:`stream` (and any method 

50 that would read from it) raise a :exc:`RuntimeError`. Useful to 

51 prevent consuming the form data in middleware, which would make 

52 it unavailable to the final application. 

53 

54 .. versionchanged:: 3.0 

55 The ``charset``, ``url_charset``, and ``encoding_errors`` parameters 

56 were removed. 

57 

58 .. versionchanged:: 2.1 

59 Old ``BaseRequest`` and mixin classes were removed. 

60 

61 .. versionchanged:: 2.1 

62 Remove the ``disable_data_descriptor`` attribute. 

63 

64 .. versionchanged:: 2.0 

65 Combine ``BaseRequest`` and mixins into a single ``Request`` 

66 class. 

67 

68 .. versionchanged:: 0.5 

69 Read-only mode is enforced with immutable classes for all data. 

70 """ 

71 

72 max_content_length: int | None = None 

73 """Stop reading data after this many bytes and raise 

74 :exc:`.RequestEntityTooLarge`. This amount of memory, plus additional object 

75 overhead, could be used during one request. 

76 

77 It's better to configure this in the WSGI server or HTTP server, rather than 

78 the WSGI application, which is why it's not set by default. Not setting it 

79 anywhere would be an issue with that application, not with Werkzeug. 

80 

81 This is applied to :attr:`stream` and anything that reads it such as 

82 :attr:`data` and :meth:`parse_form_data`. 

83 

84 .. versionadded:: 0.5 

85 """ 

86 

87 max_form_memory_size: int | None = 500_000 

88 """Stop parsing ``multipart/form-data`` if any non-file part is larger than 

89 this number of bytes, and raise :exc:`.RequestEntityTooLarge`. File parts 

90 can be larger, they are moved to disk at this limit. The default is 500kB. 

91 This is an additional check, it does not replace :attr:`max_content_length`. 

92 

93 .. versionchanged:: 3.1.9 

94 This is not applied to ``application/x-www-form-urlencoded``. 

95 

96 .. versionchanged:: 3.1 

97 Defaults to 500kb instead of unlimited. 

98 

99 .. versionadded:: 0.5 

100 """ 

101 

102 max_form_parts = 1000 

103 """Stop parsing ``multipart/form-data`` if more than this number of parts 

104 are received, and raise :exc:`.RequestEntityTooLarge`. This is useful to 

105 stop a very large number of very small fields, especially files. The 

106 default is 1000. This is an additional check, it does not replace 

107 :attr:`max_content_length`. 

108 

109 .. versionadded:: 2.2.3 

110 """ 

111 

112 #: The form data parser that should be used. Can be replaced to customize 

113 #: the form date parsing. 

114 form_data_parser_class: type[FormDataParser] = FormDataParser 

115 

116 #: The WSGI environment containing HTTP headers and information from 

117 #: the WSGI server. 

118 environ: WSGIEnvironment 

119 

120 #: Set when creating the request object. If ``True``, reading from 

121 #: the request body will cause a ``RuntimeException``. Useful to 

122 #: prevent modifying the stream from middleware. 

123 shallow: bool 

124 

125 def __init__( 

126 self, 

127 environ: WSGIEnvironment, 

128 populate_request: bool = True, 

129 shallow: bool = False, 

130 ) -> None: 

131 super().__init__( 

132 method=environ.get("REQUEST_METHOD", "GET"), 

133 scheme=environ.get("wsgi.url_scheme", "http"), 

134 server=_get_server(environ), 

135 root_path=_wsgi_decoding_dance(environ.get("SCRIPT_NAME") or ""), 

136 path=_wsgi_decoding_dance(environ.get("PATH_INFO") or ""), 

137 query_string=environ.get("QUERY_STRING", "").encode("latin1"), 

138 headers=EnvironHeaders(environ), 

139 remote_addr=environ.get("REMOTE_ADDR"), 

140 ) 

141 self.environ = environ 

142 self.shallow = shallow 

143 

144 if populate_request and not shallow: 

145 self.environ["werkzeug.request"] = self 

146 

147 @classmethod 

148 def from_values(cls, *args: t.Any, **kwargs: t.Any) -> Request: 

149 """Create a new request object based on the values provided. If 

150 environ is given missing values are filled from there. This method is 

151 useful for small scripts when you need to simulate a request from an URL. 

152 Do not use this method for unittesting, there is a full featured client 

153 object (:class:`Client`) that allows to create multipart requests, 

154 support for cookies etc. 

155 

156 This accepts the same options as the 

157 :class:`~werkzeug.test.EnvironBuilder`. 

158 

159 .. versionchanged:: 0.5 

160 This method now accepts the same arguments as 

161 :class:`~werkzeug.test.EnvironBuilder`. Because of this the 

162 `environ` parameter is now called `environ_overrides`. 

163 

164 :return: request object 

165 """ 

166 from ..test import EnvironBuilder 

167 

168 builder = EnvironBuilder(*args, **kwargs) 

169 try: 

170 return builder.get_request(cls) 

171 finally: 

172 builder.close() 

173 

174 @classmethod 

175 def application(cls, f: t.Callable[[Request], WSGIApplication]) -> WSGIApplication: 

176 """Decorate a function as responder that accepts the request as 

177 the last argument. This works like the :func:`responder` 

178 decorator but the function is passed the request object as the 

179 last argument and the request object will be closed 

180 automatically:: 

181 

182 @Request.application 

183 def my_wsgi_app(request): 

184 return Response('Hello World!') 

185 

186 As of Werkzeug 0.14 HTTP exceptions are automatically caught and 

187 converted to responses instead of failing. 

188 

189 :param f: the WSGI callable to decorate 

190 :return: a new WSGI callable 

191 """ 

192 #: return a callable that wraps the -2nd argument with the request 

193 #: and calls the function with all the arguments up to that one and 

194 #: the request. The return value is then called with the latest 

195 #: two arguments. This makes it possible to use this decorator for 

196 #: both standalone WSGI functions as well as bound methods and 

197 #: partially applied functions. 

198 from ..exceptions import HTTPException 

199 

200 @functools.wraps(f) 

201 def application(*args: t.Any) -> cabc.Iterable[bytes]: 

202 request = cls(args[-2]) 

203 with request: 

204 try: 

205 resp = f(*args[:-2] + (request,)) 

206 except HTTPException as e: 

207 resp = t.cast("WSGIApplication", e.get_response(args[-2])) 

208 return resp(*args[-2:]) 

209 

210 return t.cast("WSGIApplication", application) 

211 

212 def _get_file_stream( 

213 self, 

214 total_content_length: int | None, 

215 content_type: str | None, 

216 filename: str | None = None, 

217 content_length: int | None = None, 

218 ) -> t.IO[bytes]: 

219 """Called to get a stream for the file upload. 

220 

221 This must provide a file-like class with `read()`, `readline()` 

222 and `seek()` methods that is both writeable and readable. 

223 

224 The default implementation returns a temporary file if the total 

225 content length is higher than 500KB. Because many browsers do not 

226 provide a content length for the files only the total content 

227 length matters. 

228 

229 :param total_content_length: the total content length of all the 

230 data in the request combined. This value 

231 is guaranteed to be there. 

232 :param content_type: the mimetype of the uploaded file. 

233 :param filename: the filename of the uploaded file. May be `None`. 

234 :param content_length: the length of this file. This value is usually 

235 not provided because webbrowsers do not provide 

236 this value. 

237 """ 

238 return default_stream_factory( 

239 total_content_length=total_content_length, 

240 filename=filename, 

241 content_type=content_type, 

242 content_length=content_length, 

243 ) 

244 

245 @property 

246 def want_form_data_parsed(self) -> bool: 

247 """``True`` if the request method carries content. By default 

248 this is true if a ``Content-Type`` is sent. 

249 

250 .. versionadded:: 0.8 

251 """ 

252 return bool(self.environ.get("CONTENT_TYPE")) 

253 

254 def make_form_data_parser(self) -> FormDataParser: 

255 """Creates the form data parser. Instantiates the 

256 :attr:`form_data_parser_class` with some parameters. 

257 

258 .. versionadded:: 0.8 

259 """ 

260 return self.form_data_parser_class( 

261 stream_factory=self._get_file_stream, 

262 max_form_memory_size=self.max_form_memory_size, 

263 max_content_length=self.max_content_length, 

264 max_form_parts=self.max_form_parts, 

265 cls=self.parameter_storage_class, 

266 ) 

267 

268 def _load_form_data(self) -> None: 

269 """Method used internally to retrieve submitted data. After calling 

270 this sets `form` and `files` on the request object to multi dicts 

271 filled with the incoming form data. As a matter of fact the input 

272 stream will be empty afterwards. You can also call this method to 

273 force the parsing of the form data. 

274 

275 .. versionadded:: 0.8 

276 """ 

277 # abort early if we have already consumed the stream 

278 if "form" in self.__dict__: 

279 return 

280 

281 if self.want_form_data_parsed: 

282 parser = self.make_form_data_parser() 

283 data = parser.parse( 

284 self._get_stream_for_parsing(), 

285 self.mimetype, 

286 self.content_length, 

287 self.mimetype_params, 

288 ) 

289 else: 

290 data = ( 

291 self.stream, 

292 self.parameter_storage_class(), 

293 self.parameter_storage_class(), 

294 ) 

295 

296 # inject the values into the instance dict so that we bypass 

297 # our cached_property non-data descriptor. 

298 d = self.__dict__ 

299 d["stream"], d["form"], d["files"] = data 

300 

301 def _get_stream_for_parsing(self) -> t.IO[bytes]: 

302 """This is the same as accessing :attr:`stream` with the difference 

303 that if it finds cached data from calling :meth:`get_data` first it 

304 will create a new stream out of the cached data. 

305 

306 .. versionadded:: 0.9.3 

307 """ 

308 cached_data = getattr(self, "_cached_data", None) 

309 if cached_data is not None: 

310 return BytesIO(cached_data) 

311 return self.stream 

312 

313 def close(self) -> None: 

314 """Closes associated resources of this request object. This 

315 closes all file handles explicitly. You can also use the request 

316 object in a with statement which will automatically close it. 

317 

318 .. versionadded:: 0.9 

319 """ 

320 files = self.__dict__.get("files") 

321 for _key, value in iter_multi_items(files or ()): 

322 value.close() 

323 

324 def __enter__(self) -> Request: 

325 return self 

326 

327 def __exit__(self, exc_type, exc_value, tb) -> None: # type: ignore 

328 self.close() 

329 

330 @cached_property 

331 def stream(self) -> t.IO[bytes]: 

332 """The WSGI input stream, with safety checks. This stream can only be consumed 

333 once. 

334 

335 Use :meth:`get_data` to get the full data as bytes or text. The :attr:`data` 

336 attribute will contain the full bytes only if they do not represent form data. 

337 The :attr:`form` attribute will contain the parsed form data in that case. 

338 

339 Unlike :attr:`input_stream`, this stream guards against infinite streams or 

340 reading past :attr:`content_length` or :attr:`max_content_length`. 

341 

342 If ``max_content_length`` is set, it can be enforced on streams if 

343 ``wsgi.input_terminated`` is set. Otherwise, an empty stream is returned. 

344 

345 If the limit is reached before the underlying stream is exhausted (such as a 

346 file that is too large, or an infinite stream), the remaining contents of the 

347 stream cannot be read safely. Depending on how the server handles this, clients 

348 may show a "connection reset" failure instead of seeing the 413 response. 

349 

350 .. versionchanged:: 2.3 

351 Check ``max_content_length`` preemptively and while reading. 

352 

353 .. versionchanged:: 0.9 

354 The stream is always set (but may be consumed) even if form parsing was 

355 accessed first. 

356 """ 

357 if self.shallow: 

358 raise RuntimeError( 

359 "This request was created with 'shallow=True', reading" 

360 " from the input stream is disabled." 

361 ) 

362 

363 return get_input_stream( 

364 self.environ, max_content_length=self.max_content_length 

365 ) 

366 

367 input_stream = environ_property[t.IO[bytes]]( 

368 "wsgi.input", 

369 doc="""The raw WSGI input stream, without any safety checks. 

370 

371 This is dangerous to use. It does not guard against infinite streams or reading 

372 past :attr:`content_length` or :attr:`max_content_length`. 

373 

374 Use :attr:`stream` instead. 

375 """, 

376 ) 

377 

378 @cached_property 

379 def data(self) -> bytes: 

380 """The raw data read from :attr:`stream`. Will be empty if the request 

381 represents form data. 

382 

383 To get the raw data even if it represents form data, use :meth:`get_data`. 

384 """ 

385 return self.get_data(parse_form_data=True) 

386 

387 @t.overload 

388 def get_data( 

389 self, 

390 cache: bool = True, 

391 as_text: t.Literal[False] = False, 

392 parse_form_data: bool = False, 

393 ) -> bytes: ... 

394 

395 @t.overload 

396 def get_data( 

397 self, 

398 cache: bool = True, 

399 as_text: t.Literal[True] = ..., 

400 parse_form_data: bool = False, 

401 ) -> str: ... 

402 

403 def get_data( 

404 self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False 

405 ) -> bytes | str: 

406 """This reads the buffered incoming data from the client into one 

407 bytes object. By default this is cached but that behavior can be 

408 changed by setting `cache` to `False`. 

409 

410 Usually it's a bad idea to call this method without checking the 

411 content length first as a client could send dozens of megabytes or more 

412 to cause memory problems on the server. 

413 

414 Note that if the form data was already parsed this method will not 

415 return anything as form data parsing does not cache the data like 

416 this method does. To implicitly invoke form data parsing function 

417 set `parse_form_data` to `True`. When this is done the return value 

418 of this method will be an empty string if the form parser handles 

419 the data. This generally is not necessary as if the whole data is 

420 cached (which is the default) the form parser will used the cached 

421 data to parse the form data. Please be generally aware of checking 

422 the content length first in any case before calling this method 

423 to avoid exhausting server memory. 

424 

425 If `as_text` is set to `True` the return value will be a decoded 

426 string. 

427 

428 .. versionadded:: 0.9 

429 """ 

430 rv = getattr(self, "_cached_data", None) 

431 if rv is None: 

432 if parse_form_data: 

433 self._load_form_data() 

434 rv = self.stream.read() 

435 if cache: 

436 self._cached_data = rv 

437 if as_text: 

438 rv = rv.decode(errors="replace") 

439 return rv 

440 

441 @cached_property 

442 def form(self) -> ImmutableMultiDict[str, str]: 

443 """The form parameters. By default an 

444 :class:`~werkzeug.datastructures.ImmutableMultiDict` 

445 is returned from this function. This can be changed by setting 

446 :attr:`parameter_storage_class` to a different type. This might 

447 be necessary if the order of the form data is important. 

448 

449 Please keep in mind that file uploads will not end up here, but instead 

450 in the :attr:`files` attribute. 

451 

452 .. versionchanged:: 0.9 

453 

454 Previous to Werkzeug 0.9 this would only contain form data for POST 

455 and PUT requests. 

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 if not isinstance(d, MultiDict): 

483 d = MultiDict(d) 

484 

485 args.append(d) 

486 

487 return CombinedMultiDict(args) 

488 

489 @cached_property 

490 def files(self) -> ImmutableMultiDict[str, FileStorage]: 

491 """:class:`~werkzeug.datastructures.MultiDict` object containing 

492 all uploaded files. Each key in :attr:`files` is the name from the 

493 ``<input type="file" name="">``. Each value in :attr:`files` is a 

494 Werkzeug :class:`~werkzeug.datastructures.FileStorage` object. 

495 

496 It basically behaves like a standard file object you know from Python, 

497 with the difference that it also has a 

498 :meth:`~werkzeug.datastructures.FileStorage.save` function that can 

499 store the file on the filesystem. 

500 

501 Note that :attr:`files` will only contain data if the request method was 

502 POST, PUT or PATCH and the ``<form>`` that posted to the request had 

503 ``enctype="multipart/form-data"``. It will be empty otherwise. 

504 

505 See the :class:`~werkzeug.datastructures.MultiDict` / 

506 :class:`~werkzeug.datastructures.FileStorage` documentation for 

507 more details about the used data structure. 

508 """ 

509 self._load_form_data() 

510 return self.files 

511 

512 @property 

513 def script_root(self) -> str: 

514 """Alias for :attr:`self.root_path`. ``environ["SCRIPT_NAME"]`` 

515 without a trailing slash. 

516 """ 

517 return self.root_path 

518 

519 @cached_property 

520 def url_root(self) -> str: 

521 """Alias for :attr:`root_url`. The URL with scheme, host, and 

522 root path. For example, ``https://example.com/app/``. 

523 """ 

524 return self.root_url 

525 

526 remote_user = environ_property[str]( 

527 "REMOTE_USER", 

528 doc="""If the server supports user authentication, and the 

529 script is protected, this attribute contains the username the 

530 user has authenticated as.""", 

531 ) 

532 is_multithread = environ_property[bool]( 

533 "wsgi.multithread", 

534 doc="""boolean that is `True` if the application is served by a 

535 multithreaded WSGI server.""", 

536 ) 

537 is_multiprocess = environ_property[bool]( 

538 "wsgi.multiprocess", 

539 doc="""boolean that is `True` if the application is served by a 

540 WSGI server that spawns multiple processes.""", 

541 ) 

542 is_run_once = environ_property[bool]( 

543 "wsgi.run_once", 

544 doc="""boolean that is `True` if the application will be 

545 executed only once in a process lifetime. This is the case for 

546 CGI for example, but it's not guaranteed that the execution only 

547 happens one time.""", 

548 ) 

549 

550 # JSON 

551 

552 #: A module or other object that has ``dumps`` and ``loads`` 

553 #: functions that match the API of the built-in :mod:`json` module. 

554 json_module = json 

555 

556 @property 

557 def json(self) -> t.Any: 

558 """The parsed JSON data if :attr:`mimetype` indicates JSON 

559 (:mimetype:`application/json`, see :attr:`is_json`). 

560 

561 Calls :meth:`get_json` with default arguments. 

562 

563 If the request content type is not ``application/json``, this 

564 will raise a 415 Unsupported Media Type error. 

565 

566 .. versionchanged:: 2.3 

567 Raise a 415 error instead of 400. 

568 

569 .. versionchanged:: 2.1 

570 Raise a 400 error if the content type is incorrect. 

571 """ 

572 return self.get_json() 

573 

574 # Cached values for ``(silent=False, silent=True)``. Initialized 

575 # with sentinel values. 

576 _cached_json: tuple[t.Any, t.Any] = (Ellipsis, Ellipsis) 

577 

578 @t.overload 

579 def get_json( 

580 self, force: bool = ..., silent: t.Literal[False] = ..., cache: bool = ... 

581 ) -> t.Any: ... 

582 

583 @t.overload 

584 def get_json( 

585 self, force: bool = ..., silent: bool = ..., cache: bool = ... 

586 ) -> t.Any | None: ... 

587 

588 def get_json( 

589 self, force: bool = False, silent: bool = False, cache: bool = True 

590 ) -> t.Any | None: 

591 """Parse :attr:`data` as JSON. 

592 

593 If the mimetype does not indicate JSON 

594 (:mimetype:`application/json`, see :attr:`is_json`), or parsing 

595 fails, :meth:`on_json_loading_failed` is called and 

596 its return value is used as the return value. By default this 

597 raises a 415 Unsupported Media Type resp. 

598 

599 :param force: Ignore the mimetype and always try to parse JSON. 

600 :param silent: Silence mimetype and parsing errors, and 

601 return ``None`` instead. 

602 :param cache: Store the parsed JSON to return for subsequent 

603 calls. 

604 

605 .. versionchanged:: 2.3 

606 Raise a 415 error instead of 400. 

607 

608 .. versionchanged:: 2.1 

609 Raise a 400 error if the content type is incorrect. 

610 """ 

611 if cache and self._cached_json[silent] is not Ellipsis: 

612 return self._cached_json[silent] 

613 

614 if not (force or self.is_json): 

615 if not silent: 

616 return self.on_json_loading_failed(None) 

617 else: 

618 return None 

619 

620 data = self.get_data(cache=cache) 

621 

622 try: 

623 rv = self.json_module.loads(data) 

624 except ValueError as e: 

625 if silent: 

626 rv = None 

627 

628 if cache: 

629 normal_rv, _ = self._cached_json 

630 self._cached_json = (normal_rv, rv) 

631 else: 

632 rv = self.on_json_loading_failed(e) 

633 

634 if cache: 

635 _, silent_rv = self._cached_json 

636 self._cached_json = (rv, silent_rv) 

637 else: 

638 if cache: 

639 self._cached_json = (rv, rv) 

640 

641 return rv 

642 

643 def on_json_loading_failed(self, e: ValueError | None) -> t.Any: 

644 """Called if :meth:`get_json` fails and isn't silenced. 

645 

646 If this method returns a value, it is used as the return value 

647 for :meth:`get_json`. The default implementation raises 

648 :exc:`~werkzeug.exceptions.BadRequest`. 

649 

650 :param e: If parsing failed, this is the exception. It will be 

651 ``None`` if the content type wasn't ``application/json``. 

652 

653 .. versionchanged:: 2.3 

654 Raise a 415 error instead of 400. 

655 """ 

656 if e is not None: 

657 raise BadRequest(f"Failed to decode JSON object: {e}") 

658 

659 raise UnsupportedMediaType( 

660 "Did not attempt to load JSON data because the request" 

661 " Content-Type was not 'application/json'." 

662 )