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

179 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-09 07:17 +0000

1from __future__ import annotations 

2 

3import functools 

4import json 

5import typing as t 

6from io import BytesIO 

7 

8from .._internal import _wsgi_decoding_dance 

9from ..datastructures import CombinedMultiDict 

10from ..datastructures import EnvironHeaders 

11from ..datastructures import FileStorage 

12from ..datastructures import ImmutableMultiDict 

13from ..datastructures import iter_multi_items 

14from ..datastructures import MultiDict 

15from ..exceptions import BadRequest 

16from ..exceptions import UnsupportedMediaType 

17from ..formparser import default_stream_factory 

18from ..formparser import FormDataParser 

19from ..sansio.request import Request as _SansIORequest 

20from ..utils import cached_property 

21from ..utils import environ_property 

22from ..wsgi import _get_server 

23from ..wsgi import get_input_stream 

24 

25if t.TYPE_CHECKING: 

26 from _typeshed.wsgi import WSGIApplication 

27 from _typeshed.wsgi import WSGIEnvironment 

28 

29 

30class Request(_SansIORequest): 

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

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

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

34 requests object is read-only. 

35 

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

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

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

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

40 :attr:`charset`. 

41 

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

43 contains information about the server configuration and client 

44 request. 

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

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

47 debugging. 

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

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

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

51 it unavailable to the final application. 

52 

53 .. versionchanged:: 3.0 

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

55 were removed. 

56 

57 .. versionchanged:: 2.1 

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

59 

60 .. versionchanged:: 2.1 

61 Remove the ``disable_data_descriptor`` attribute. 

62 

63 .. versionchanged:: 2.0 

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

65 class. 

66 

67 .. versionchanged:: 0.5 

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

69 """ 

70 

71 #: the maximum content length. This is forwarded to the form data 

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

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

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

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

76 #: 

77 #: .. versionadded:: 0.5 

78 max_content_length: int | None = None 

79 

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

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

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

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

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

85 #: 

86 #: .. versionadded:: 0.5 

87 max_form_memory_size: int | None = None 

88 

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

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

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

92 #: 

93 #: .. versionadded:: 2.2.3 

94 max_form_parts = 1000 

95 

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

97 #: the form date parsing. 

98 form_data_parser_class: type[FormDataParser] = FormDataParser 

99 

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

101 #: the WSGI server. 

102 environ: WSGIEnvironment 

103 

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

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

106 #: prevent modifying the stream from middleware. 

107 shallow: bool 

108 

109 def __init__( 

110 self, 

111 environ: WSGIEnvironment, 

112 populate_request: bool = True, 

113 shallow: bool = False, 

114 ) -> None: 

115 super().__init__( 

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

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

118 server=_get_server(environ), 

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

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

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

122 headers=EnvironHeaders(environ), 

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

124 ) 

125 self.environ = environ 

126 self.shallow = shallow 

127 

128 if populate_request and not shallow: 

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

130 

131 @classmethod 

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

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

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

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

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

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

138 support for cookies etc. 

139 

140 This accepts the same options as the 

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

142 

143 .. versionchanged:: 0.5 

144 This method now accepts the same arguments as 

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

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

147 

148 :return: request object 

149 """ 

150 from ..test import EnvironBuilder 

151 

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

153 try: 

154 return builder.get_request(cls) 

155 finally: 

156 builder.close() 

157 

158 @classmethod 

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

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

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

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

163 last argument and the request object will be closed 

164 automatically:: 

165 

166 @Request.application 

167 def my_wsgi_app(request): 

168 return Response('Hello World!') 

169 

170 As of Werkzeug 0.14 HTTP exceptions are automatically caught and 

171 converted to responses instead of failing. 

172 

173 :param f: the WSGI callable to decorate 

174 :return: a new WSGI callable 

175 """ 

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

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

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

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

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

181 #: partially applied functions. 

182 from ..exceptions import HTTPException 

183 

184 @functools.wraps(f) 

185 def application(*args): # type: ignore 

186 request = cls(args[-2]) 

187 with request: 

188 try: 

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

190 except HTTPException as e: 

191 resp = e.get_response(args[-2]) 

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

193 

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

195 

196 def _get_file_stream( 

197 self, 

198 total_content_length: int | None, 

199 content_type: str | None, 

200 filename: str | None = None, 

201 content_length: int | None = None, 

202 ) -> t.IO[bytes]: 

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

204 

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

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

207 

208 The default implementation returns a temporary file if the total 

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

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

211 length matters. 

212 

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

214 data in the request combined. This value 

215 is guaranteed to be there. 

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

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

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

219 not provided because webbrowsers do not provide 

220 this value. 

221 """ 

222 return default_stream_factory( 

223 total_content_length=total_content_length, 

224 filename=filename, 

225 content_type=content_type, 

226 content_length=content_length, 

227 ) 

228 

229 @property 

230 def want_form_data_parsed(self) -> bool: 

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

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

233 

234 .. versionadded:: 0.8 

235 """ 

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

237 

238 def make_form_data_parser(self) -> FormDataParser: 

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

240 :attr:`form_data_parser_class` with some parameters. 

241 

242 .. versionadded:: 0.8 

243 """ 

244 return self.form_data_parser_class( 

245 stream_factory=self._get_file_stream, 

246 max_form_memory_size=self.max_form_memory_size, 

247 max_content_length=self.max_content_length, 

248 max_form_parts=self.max_form_parts, 

249 cls=self.parameter_storage_class, 

250 ) 

251 

252 def _load_form_data(self) -> None: 

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

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

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

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

257 force the parsing of the form data. 

258 

259 .. versionadded:: 0.8 

260 """ 

261 # abort early if we have already consumed the stream 

262 if "form" in self.__dict__: 

263 return 

264 

265 if self.want_form_data_parsed: 

266 parser = self.make_form_data_parser() 

267 data = parser.parse( 

268 self._get_stream_for_parsing(), 

269 self.mimetype, 

270 self.content_length, 

271 self.mimetype_params, 

272 ) 

273 else: 

274 data = ( 

275 self.stream, 

276 self.parameter_storage_class(), 

277 self.parameter_storage_class(), 

278 ) 

279 

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

281 # our cached_property non-data descriptor. 

282 d = self.__dict__ 

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

284 

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

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

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

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

289 

290 .. versionadded:: 0.9.3 

291 """ 

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

293 if cached_data is not None: 

294 return BytesIO(cached_data) 

295 return self.stream 

296 

297 def close(self) -> None: 

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

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

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

301 

302 .. versionadded:: 0.9 

303 """ 

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

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

306 value.close() 

307 

308 def __enter__(self) -> Request: 

309 return self 

310 

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

312 self.close() 

313 

314 @cached_property 

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

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

317 once. 

318 

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

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

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

322 

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

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

325 

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

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

328 

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

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

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

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

333 

334 .. versionchanged:: 2.3 

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

336 

337 .. versionchanged:: 0.9 

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

339 accessed first. 

340 """ 

341 if self.shallow: 

342 raise RuntimeError( 

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

344 " from the input stream is disabled." 

345 ) 

346 

347 return get_input_stream( 

348 self.environ, max_content_length=self.max_content_length 

349 ) 

350 

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

352 "wsgi.input", 

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

354 

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

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

357 

358 Use :attr:`stream` instead. 

359 """, 

360 ) 

361 

362 @cached_property 

363 def data(self) -> bytes: 

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

365 represents form data. 

366 

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

368 """ 

369 return self.get_data(parse_form_data=True) 

370 

371 @t.overload 

372 def get_data( # type: ignore 

373 self, 

374 cache: bool = True, 

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

376 parse_form_data: bool = False, 

377 ) -> bytes: 

378 ... 

379 

380 @t.overload 

381 def get_data( 

382 self, 

383 cache: bool = True, 

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

385 parse_form_data: bool = False, 

386 ) -> str: 

387 ... 

388 

389 def get_data( 

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

391 ) -> bytes | str: 

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

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

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

395 

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

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

398 to cause memory problems on the server. 

399 

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

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

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

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

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

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

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

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

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

409 to avoid exhausting server memory. 

410 

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

412 string. 

413 

414 .. versionadded:: 0.9 

415 """ 

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

417 if rv is None: 

418 if parse_form_data: 

419 self._load_form_data() 

420 rv = self.stream.read() 

421 if cache: 

422 self._cached_data = rv 

423 if as_text: 

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

425 return rv 

426 

427 @cached_property 

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

429 """The form parameters. By default an 

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

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

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

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

434 

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

436 in the :attr:`files` attribute. 

437 

438 .. versionchanged:: 0.9 

439 

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

441 and PUT requests. 

442 """ 

443 self._load_form_data() 

444 return self.form 

445 

446 @cached_property 

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

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

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

450 

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

452 

453 .. versionchanged:: 2.0 

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

455 """ 

456 sources = [self.args] 

457 

458 if self.method != "GET": 

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

460 # might not treat that differently than a normal GET 

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

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

463 sources.append(self.form) 

464 

465 args = [] 

466 

467 for d in sources: 

468 if not isinstance(d, MultiDict): 

469 d = MultiDict(d) 

470 

471 args.append(d) 

472 

473 return CombinedMultiDict(args) 

474 

475 @cached_property 

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

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

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

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

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

481 

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

483 with the difference that it also has a 

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

485 store the file on the filesystem. 

486 

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

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

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

490 

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

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

493 more details about the used data structure. 

494 """ 

495 self._load_form_data() 

496 return self.files 

497 

498 @property 

499 def script_root(self) -> str: 

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

501 without a trailing slash. 

502 """ 

503 return self.root_path 

504 

505 @cached_property 

506 def url_root(self) -> str: 

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

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

509 """ 

510 return self.root_url 

511 

512 remote_user = environ_property[str]( 

513 "REMOTE_USER", 

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

515 script is protected, this attribute contains the username the 

516 user has authenticated as.""", 

517 ) 

518 is_multithread = environ_property[bool]( 

519 "wsgi.multithread", 

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

521 multithreaded WSGI server.""", 

522 ) 

523 is_multiprocess = environ_property[bool]( 

524 "wsgi.multiprocess", 

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

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

527 ) 

528 is_run_once = environ_property[bool]( 

529 "wsgi.run_once", 

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

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

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

533 happens one time.""", 

534 ) 

535 

536 # JSON 

537 

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

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

540 json_module = json 

541 

542 @property 

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

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

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

546 

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

548 

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

550 will raise a 415 Unsupported Media Type error. 

551 

552 .. versionchanged:: 2.3 

553 Raise a 415 error instead of 400. 

554 

555 .. versionchanged:: 2.1 

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

557 """ 

558 return self.get_json() 

559 

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

561 # with sentinel values. 

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

563 

564 @t.overload 

565 def get_json( 

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

567 ) -> t.Any: 

568 ... 

569 

570 @t.overload 

571 def get_json( 

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

573 ) -> t.Any | None: 

574 ... 

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 )