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

182 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-09 06:08 +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:: 2.1 

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

55 

56 .. versionchanged:: 2.1 

57 Remove the ``disable_data_descriptor`` attribute. 

58 

59 .. versionchanged:: 2.0 

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

61 class. 

62 

63 .. versionchanged:: 0.5 

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

65 """ 

66 

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

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

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

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

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

72 #: 

73 #: .. versionadded:: 0.5 

74 max_content_length: int | None = None 

75 

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

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

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

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

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

81 #: 

82 #: .. versionadded:: 0.5 

83 max_form_memory_size: int | None = None 

84 

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

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

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

88 #: 

89 #: .. versionadded:: 2.2.3 

90 max_form_parts = 1000 

91 

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

93 #: the form date parsing. 

94 form_data_parser_class: type[FormDataParser] = FormDataParser 

95 

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

97 #: the WSGI server. 

98 environ: WSGIEnvironment 

99 

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

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

102 #: prevent modifying the stream from middleware. 

103 shallow: bool 

104 

105 def __init__( 

106 self, 

107 environ: WSGIEnvironment, 

108 populate_request: bool = True, 

109 shallow: bool = False, 

110 ) -> None: 

111 super().__init__( 

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

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

114 server=_get_server(environ), 

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

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

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

118 headers=EnvironHeaders(environ), 

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

120 ) 

121 self.environ = environ 

122 self.shallow = shallow 

123 

124 if populate_request and not shallow: 

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

126 

127 @classmethod 

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

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

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

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

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

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

134 support for cookies etc. 

135 

136 This accepts the same options as the 

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

138 

139 .. versionchanged:: 0.5 

140 This method now accepts the same arguments as 

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

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

143 

144 :return: request object 

145 """ 

146 from ..test import EnvironBuilder 

147 

148 kwargs.setdefault( 

149 "charset", cls.charset if not isinstance(cls.charset, property) else None 

150 ) 

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

152 try: 

153 return builder.get_request(cls) 

154 finally: 

155 builder.close() 

156 

157 @classmethod 

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

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

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

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

162 last argument and the request object will be closed 

163 automatically:: 

164 

165 @Request.application 

166 def my_wsgi_app(request): 

167 return Response('Hello World!') 

168 

169 As of Werkzeug 0.14 HTTP exceptions are automatically caught and 

170 converted to responses instead of failing. 

171 

172 :param f: the WSGI callable to decorate 

173 :return: a new WSGI callable 

174 """ 

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

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

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

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

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

180 #: partially applied functions. 

181 from ..exceptions import HTTPException 

182 

183 @functools.wraps(f) 

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

185 request = cls(args[-2]) 

186 with request: 

187 try: 

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

189 except HTTPException as e: 

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

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

192 

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

194 

195 def _get_file_stream( 

196 self, 

197 total_content_length: int | None, 

198 content_type: str | None, 

199 filename: str | None = None, 

200 content_length: int | None = None, 

201 ) -> t.IO[bytes]: 

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

203 

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

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

206 

207 The default implementation returns a temporary file if the total 

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

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

210 length matters. 

211 

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

213 data in the request combined. This value 

214 is guaranteed to be there. 

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

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

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

218 not provided because webbrowsers do not provide 

219 this value. 

220 """ 

221 return default_stream_factory( 

222 total_content_length=total_content_length, 

223 filename=filename, 

224 content_type=content_type, 

225 content_length=content_length, 

226 ) 

227 

228 @property 

229 def want_form_data_parsed(self) -> bool: 

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

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

232 

233 .. versionadded:: 0.8 

234 """ 

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

236 

237 def make_form_data_parser(self) -> FormDataParser: 

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

239 :attr:`form_data_parser_class` with some parameters. 

240 

241 .. versionadded:: 0.8 

242 """ 

243 charset = self._charset if self._charset != "utf-8" else None 

244 errors = self._encoding_errors if self._encoding_errors != "replace" else None 

245 return self.form_data_parser_class( 

246 stream_factory=self._get_file_stream, 

247 charset=charset, 

248 errors=errors, 

249 max_form_memory_size=self.max_form_memory_size, 

250 max_content_length=self.max_content_length, 

251 max_form_parts=self.max_form_parts, 

252 cls=self.parameter_storage_class, 

253 ) 

254 

255 def _load_form_data(self) -> None: 

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

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

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

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

260 force the parsing of the form data. 

261 

262 .. versionadded:: 0.8 

263 """ 

264 # abort early if we have already consumed the stream 

265 if "form" in self.__dict__: 

266 return 

267 

268 if self.want_form_data_parsed: 

269 parser = self.make_form_data_parser() 

270 data = parser.parse( 

271 self._get_stream_for_parsing(), 

272 self.mimetype, 

273 self.content_length, 

274 self.mimetype_params, 

275 ) 

276 else: 

277 data = ( 

278 self.stream, 

279 self.parameter_storage_class(), 

280 self.parameter_storage_class(), 

281 ) 

282 

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

284 # our cached_property non-data descriptor. 

285 d = self.__dict__ 

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

287 

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

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

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

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

292 

293 .. versionadded:: 0.9.3 

294 """ 

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

296 if cached_data is not None: 

297 return BytesIO(cached_data) 

298 return self.stream 

299 

300 def close(self) -> None: 

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

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

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

304 

305 .. versionadded:: 0.9 

306 """ 

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

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

309 value.close() 

310 

311 def __enter__(self) -> Request: 

312 return self 

313 

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

315 self.close() 

316 

317 @cached_property 

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

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

320 once. 

321 

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

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

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

325 

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

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

328 

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

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

331 

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

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

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

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

336 

337 .. versionchanged:: 2.3 

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

339 

340 .. versionchanged:: 0.9 

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

342 accessed first. 

343 """ 

344 if self.shallow: 

345 raise RuntimeError( 

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

347 " from the input stream is disabled." 

348 ) 

349 

350 return get_input_stream( 

351 self.environ, max_content_length=self.max_content_length 

352 ) 

353 

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

355 "wsgi.input", 

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

357 

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

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

360 

361 Use :attr:`stream` instead. 

362 """, 

363 ) 

364 

365 @cached_property 

366 def data(self) -> bytes: 

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

368 represents form data. 

369 

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

371 """ 

372 return self.get_data(parse_form_data=True) 

373 

374 @t.overload 

375 def get_data( # type: ignore 

376 self, 

377 cache: bool = True, 

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

379 parse_form_data: bool = False, 

380 ) -> bytes: 

381 ... 

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 

392 def get_data( 

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

394 ) -> bytes | str: 

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

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

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

398 

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

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

401 to cause memory problems on the server. 

402 

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

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

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

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

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

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

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

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

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

412 to avoid exhausting server memory. 

413 

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

415 string. 

416 

417 .. versionadded:: 0.9 

418 """ 

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

420 if rv is None: 

421 if parse_form_data: 

422 self._load_form_data() 

423 rv = self.stream.read() 

424 if cache: 

425 self._cached_data = rv 

426 if as_text: 

427 rv = rv.decode(self._charset, self._encoding_errors) 

428 return rv 

429 

430 @cached_property 

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

432 """The form parameters. By default an 

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

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

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

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

437 

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

439 in the :attr:`files` attribute. 

440 

441 .. versionchanged:: 0.9 

442 

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

444 and PUT requests. 

445 """ 

446 self._load_form_data() 

447 return self.form 

448 

449 @cached_property 

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

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

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

453 

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

455 

456 .. versionchanged:: 2.0 

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

458 """ 

459 sources = [self.args] 

460 

461 if self.method != "GET": 

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

463 # might not treat that differently than a normal GET 

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

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

466 sources.append(self.form) 

467 

468 args = [] 

469 

470 for d in sources: 

471 if not isinstance(d, MultiDict): 

472 d = MultiDict(d) 

473 

474 args.append(d) 

475 

476 return CombinedMultiDict(args) 

477 

478 @cached_property 

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

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

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

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

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

484 

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

486 with the difference that it also has a 

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

488 store the file on the filesystem. 

489 

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

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

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

493 

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

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

496 more details about the used data structure. 

497 """ 

498 self._load_form_data() 

499 return self.files 

500 

501 @property 

502 def script_root(self) -> str: 

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

504 without a trailing slash. 

505 """ 

506 return self.root_path 

507 

508 @cached_property 

509 def url_root(self) -> str: 

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

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

512 """ 

513 return self.root_url 

514 

515 remote_user = environ_property[str]( 

516 "REMOTE_USER", 

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

518 script is protected, this attribute contains the username the 

519 user has authenticated as.""", 

520 ) 

521 is_multithread = environ_property[bool]( 

522 "wsgi.multithread", 

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

524 multithreaded WSGI server.""", 

525 ) 

526 is_multiprocess = environ_property[bool]( 

527 "wsgi.multiprocess", 

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

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

530 ) 

531 is_run_once = environ_property[bool]( 

532 "wsgi.run_once", 

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

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

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

536 happens one time.""", 

537 ) 

538 

539 # JSON 

540 

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

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

543 json_module = json 

544 

545 @property 

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

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

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

549 

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

551 

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

553 will raise a 415 Unsupported Media Type error. 

554 

555 .. versionchanged:: 2.3 

556 Raise a 415 error instead of 400. 

557 

558 .. versionchanged:: 2.1 

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

560 """ 

561 return self.get_json() 

562 

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

564 # with sentinel values. 

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

566 

567 @t.overload 

568 def get_json( 

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

570 ) -> t.Any: 

571 ... 

572 

573 @t.overload 

574 def get_json( 

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

576 ) -> t.Any | None: 

577 ... 

578 

579 def get_json( 

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

581 ) -> t.Any | None: 

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

583 

584 If the mimetype does not indicate JSON 

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

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

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

588 raises a 415 Unsupported Media Type resp. 

589 

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

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

592 return ``None`` instead. 

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

594 calls. 

595 

596 .. versionchanged:: 2.3 

597 Raise a 415 error instead of 400. 

598 

599 .. versionchanged:: 2.1 

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

601 """ 

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

603 return self._cached_json[silent] 

604 

605 if not (force or self.is_json): 

606 if not silent: 

607 return self.on_json_loading_failed(None) 

608 else: 

609 return None 

610 

611 data = self.get_data(cache=cache) 

612 

613 try: 

614 rv = self.json_module.loads(data) 

615 except ValueError as e: 

616 if silent: 

617 rv = None 

618 

619 if cache: 

620 normal_rv, _ = self._cached_json 

621 self._cached_json = (normal_rv, rv) 

622 else: 

623 rv = self.on_json_loading_failed(e) 

624 

625 if cache: 

626 _, silent_rv = self._cached_json 

627 self._cached_json = (rv, silent_rv) 

628 else: 

629 if cache: 

630 self._cached_json = (rv, rv) 

631 

632 return rv 

633 

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

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

636 

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

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

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

640 

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

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

643 

644 .. versionchanged:: 2.3 

645 Raise a 415 error instead of 400. 

646 """ 

647 if e is not None: 

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

649 

650 raise UnsupportedMediaType( 

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

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

653 )