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

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

176 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 #: the maximum content length. This is forwarded to the form data 

73 #: parsing function (:func:`parse_form_data`). When set and the 

74 #: :attr:`form` or :attr:`files` attribute is accessed and the 

75 #: parsing fails because more than the specified value is transmitted 

76 #: a :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. 

77 #: 

78 #: .. versionadded:: 0.5 

79 max_content_length: int | None = None 

80 

81 #: the maximum form field size. This is forwarded to the form data 

82 #: parsing function (:func:`parse_form_data`). When set and the 

83 #: :attr:`form` or :attr:`files` attribute is accessed and the 

84 #: data in memory for post data is longer than the specified value a 

85 #: :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. 

86 #: 

87 #: .. versionchanged:: 3.1 

88 #: Defaults to 500kB instead of unlimited. 

89 #: 

90 #: .. versionadded:: 0.5 

91 max_form_memory_size: int | None = 500_000 

92 

93 #: The maximum number of multipart parts to parse, passed to 

94 #: :attr:`form_data_parser_class`. Parsing form data with more than this 

95 #: many parts will raise :exc:`~.RequestEntityTooLarge`. 

96 #: 

97 #: .. versionadded:: 2.2.3 

98 max_form_parts = 1000 

99 

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

101 #: the form date parsing. 

102 form_data_parser_class: type[FormDataParser] = FormDataParser 

103 

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

105 #: the WSGI server. 

106 environ: WSGIEnvironment 

107 

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

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

110 #: prevent modifying the stream from middleware. 

111 shallow: bool 

112 

113 def __init__( 

114 self, 

115 environ: WSGIEnvironment, 

116 populate_request: bool = True, 

117 shallow: bool = False, 

118 ) -> None: 

119 super().__init__( 

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

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

122 server=_get_server(environ), 

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

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

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

126 headers=EnvironHeaders(environ), 

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

128 ) 

129 self.environ = environ 

130 self.shallow = shallow 

131 

132 if populate_request and not shallow: 

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

134 

135 @classmethod 

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

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

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

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

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

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

142 support for cookies etc. 

143 

144 This accepts the same options as the 

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

146 

147 .. versionchanged:: 0.5 

148 This method now accepts the same arguments as 

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

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

151 

152 :return: request object 

153 """ 

154 from ..test import EnvironBuilder 

155 

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

157 try: 

158 return builder.get_request(cls) 

159 finally: 

160 builder.close() 

161 

162 @classmethod 

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

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

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

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

167 last argument and the request object will be closed 

168 automatically:: 

169 

170 @Request.application 

171 def my_wsgi_app(request): 

172 return Response('Hello World!') 

173 

174 As of Werkzeug 0.14 HTTP exceptions are automatically caught and 

175 converted to responses instead of failing. 

176 

177 :param f: the WSGI callable to decorate 

178 :return: a new WSGI callable 

179 """ 

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

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

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

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

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

185 #: partially applied functions. 

186 from ..exceptions import HTTPException 

187 

188 @functools.wraps(f) 

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

190 request = cls(args[-2]) 

191 with request: 

192 try: 

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

194 except HTTPException as e: 

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

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

197 

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

199 

200 def _get_file_stream( 

201 self, 

202 total_content_length: int | None, 

203 content_type: str | None, 

204 filename: str | None = None, 

205 content_length: int | None = None, 

206 ) -> t.IO[bytes]: 

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

208 

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

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

211 

212 The default implementation returns a temporary file if the total 

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

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

215 length matters. 

216 

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

218 data in the request combined. This value 

219 is guaranteed to be there. 

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

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

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

223 not provided because webbrowsers do not provide 

224 this value. 

225 """ 

226 return default_stream_factory( 

227 total_content_length=total_content_length, 

228 filename=filename, 

229 content_type=content_type, 

230 content_length=content_length, 

231 ) 

232 

233 @property 

234 def want_form_data_parsed(self) -> bool: 

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

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

237 

238 .. versionadded:: 0.8 

239 """ 

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

241 

242 def make_form_data_parser(self) -> FormDataParser: 

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

244 :attr:`form_data_parser_class` with some parameters. 

245 

246 .. versionadded:: 0.8 

247 """ 

248 return self.form_data_parser_class( 

249 stream_factory=self._get_file_stream, 

250 max_form_memory_size=self.max_form_memory_size, 

251 max_content_length=self.max_content_length, 

252 max_form_parts=self.max_form_parts, 

253 cls=self.parameter_storage_class, 

254 ) 

255 

256 def _load_form_data(self) -> None: 

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

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

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

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

261 force the parsing of the form data. 

262 

263 .. versionadded:: 0.8 

264 """ 

265 # abort early if we have already consumed the stream 

266 if "form" in self.__dict__: 

267 return 

268 

269 if self.want_form_data_parsed: 

270 parser = self.make_form_data_parser() 

271 data = parser.parse( 

272 self._get_stream_for_parsing(), 

273 self.mimetype, 

274 self.content_length, 

275 self.mimetype_params, 

276 ) 

277 else: 

278 data = ( 

279 self.stream, 

280 self.parameter_storage_class(), 

281 self.parameter_storage_class(), 

282 ) 

283 

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

285 # our cached_property non-data descriptor. 

286 d = self.__dict__ 

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

288 

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

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

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

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

293 

294 .. versionadded:: 0.9.3 

295 """ 

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

297 if cached_data is not None: 

298 return BytesIO(cached_data) 

299 return self.stream 

300 

301 def close(self) -> None: 

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

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

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

305 

306 .. versionadded:: 0.9 

307 """ 

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

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

310 value.close() 

311 

312 def __enter__(self) -> Request: 

313 return self 

314 

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

316 self.close() 

317 

318 @cached_property 

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

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

321 once. 

322 

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

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

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

326 

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

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

329 

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

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

332 

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

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

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

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

337 

338 .. versionchanged:: 2.3 

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

340 

341 .. versionchanged:: 0.9 

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

343 accessed first. 

344 """ 

345 if self.shallow: 

346 raise RuntimeError( 

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

348 " from the input stream is disabled." 

349 ) 

350 

351 return get_input_stream( 

352 self.environ, max_content_length=self.max_content_length 

353 ) 

354 

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

356 "wsgi.input", 

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

358 

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

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

361 

362 Use :attr:`stream` instead. 

363 """, 

364 ) 

365 

366 @cached_property 

367 def data(self) -> bytes: 

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

369 represents form data. 

370 

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

372 """ 

373 return self.get_data(parse_form_data=True) 

374 

375 @t.overload 

376 def get_data( 

377 self, 

378 cache: bool = True, 

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

380 parse_form_data: bool = False, 

381 ) -> bytes: ... 

382 

383 @t.overload 

384 def get_data( 

385 self, 

386 cache: bool = True, 

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

388 parse_form_data: bool = False, 

389 ) -> str: ... 

390 

391 def get_data( 

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

393 ) -> bytes | str: 

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

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

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

397 

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

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

400 to cause memory problems on the server. 

401 

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

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

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

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

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

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

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

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

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

411 to avoid exhausting server memory. 

412 

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

414 string. 

415 

416 .. versionadded:: 0.9 

417 """ 

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

419 if rv is None: 

420 if parse_form_data: 

421 self._load_form_data() 

422 rv = self.stream.read() 

423 if cache: 

424 self._cached_data = rv 

425 if as_text: 

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

427 return rv 

428 

429 @cached_property 

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

431 """The form parameters. By default an 

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

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

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

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

436 

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

438 in the :attr:`files` attribute. 

439 

440 .. versionchanged:: 0.9 

441 

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

443 and PUT requests. 

444 """ 

445 self._load_form_data() 

446 return self.form 

447 

448 @cached_property 

449 def values(self) -> CombinedMultiDict[str, str]: 

450 """A :class:`werkzeug.datastructures.CombinedMultiDict` that 

451 combines :attr:`args` and :attr:`form`. 

452 

453 For GET requests, only ``args`` are present, not ``form``. 

454 

455 .. versionchanged:: 2.0 

456 For GET requests, only ``args`` are present, not ``form``. 

457 """ 

458 sources = [self.args] 

459 

460 if self.method != "GET": 

461 # GET requests can have a body, and some caching proxies 

462 # might not treat that differently than a normal GET 

463 # request, allowing form data to "invisibly" affect the 

464 # cache without indication in the query string / URL. 

465 sources.append(self.form) 

466 

467 args = [] 

468 

469 for d in sources: 

470 if not isinstance(d, MultiDict): 

471 d = MultiDict(d) 

472 

473 args.append(d) 

474 

475 return CombinedMultiDict(args) 

476 

477 @cached_property 

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

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

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

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

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

483 

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

485 with the difference that it also has a 

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

487 store the file on the filesystem. 

488 

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

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

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

492 

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

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

495 more details about the used data structure. 

496 """ 

497 self._load_form_data() 

498 return self.files 

499 

500 @property 

501 def script_root(self) -> str: 

502 """Alias for :attr:`self.root_path`. ``environ["SCRIPT_ROOT"]`` 

503 without a trailing slash. 

504 """ 

505 return self.root_path 

506 

507 @cached_property 

508 def url_root(self) -> str: 

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

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

511 """ 

512 return self.root_url 

513 

514 remote_user = environ_property[str]( 

515 "REMOTE_USER", 

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

517 script is protected, this attribute contains the username the 

518 user has authenticated as.""", 

519 ) 

520 is_multithread = environ_property[bool]( 

521 "wsgi.multithread", 

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

523 multithreaded WSGI server.""", 

524 ) 

525 is_multiprocess = environ_property[bool]( 

526 "wsgi.multiprocess", 

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

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

529 ) 

530 is_run_once = environ_property[bool]( 

531 "wsgi.run_once", 

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

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

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

535 happens one time.""", 

536 ) 

537 

538 # JSON 

539 

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

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

542 json_module = json 

543 

544 @property 

545 def json(self) -> t.Any | None: 

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

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

548 

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

550 

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

552 will raise a 415 Unsupported Media Type error. 

553 

554 .. versionchanged:: 2.3 

555 Raise a 415 error instead of 400. 

556 

557 .. versionchanged:: 2.1 

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

559 """ 

560 return self.get_json() 

561 

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

563 # with sentinel values. 

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

565 

566 @t.overload 

567 def get_json( 

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

569 ) -> t.Any: ... 

570 

571 @t.overload 

572 def get_json( 

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

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

575 

576 def get_json( 

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

578 ) -> t.Any | None: 

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

580 

581 If the mimetype does not indicate JSON 

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

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

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

585 raises a 415 Unsupported Media Type resp. 

586 

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

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

589 return ``None`` instead. 

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

591 calls. 

592 

593 .. versionchanged:: 2.3 

594 Raise a 415 error instead of 400. 

595 

596 .. versionchanged:: 2.1 

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

598 """ 

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

600 return self._cached_json[silent] 

601 

602 if not (force or self.is_json): 

603 if not silent: 

604 return self.on_json_loading_failed(None) 

605 else: 

606 return None 

607 

608 data = self.get_data(cache=cache) 

609 

610 try: 

611 rv = self.json_module.loads(data) 

612 except ValueError as e: 

613 if silent: 

614 rv = None 

615 

616 if cache: 

617 normal_rv, _ = self._cached_json 

618 self._cached_json = (normal_rv, rv) 

619 else: 

620 rv = self.on_json_loading_failed(e) 

621 

622 if cache: 

623 _, silent_rv = self._cached_json 

624 self._cached_json = (rv, silent_rv) 

625 else: 

626 if cache: 

627 self._cached_json = (rv, rv) 

628 

629 return rv 

630 

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

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

633 

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

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

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

637 

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

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

640 

641 .. versionchanged:: 2.3 

642 Raise a 415 error instead of 400. 

643 """ 

644 if e is not None: 

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

646 

647 raise UnsupportedMediaType( 

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

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

650 )