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

181 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1import functools 

2import json 

3import typing 

4import typing as t 

5from io import BytesIO 

6 

7from .._internal import _wsgi_decoding_dance 

8from ..datastructures import CombinedMultiDict 

9from ..datastructures import EnvironHeaders 

10from ..datastructures import FileStorage 

11from ..datastructures import ImmutableMultiDict 

12from ..datastructures import iter_multi_items 

13from ..datastructures import MultiDict 

14from ..formparser import default_stream_factory 

15from ..formparser import FormDataParser 

16from ..sansio.request import Request as _SansIORequest 

17from ..utils import cached_property 

18from ..utils import environ_property 

19from ..wsgi import _get_server 

20from ..wsgi import get_input_stream 

21from werkzeug.exceptions import BadRequest 

22 

23if t.TYPE_CHECKING: 

24 import typing_extensions as te 

25 from _typeshed.wsgi import WSGIApplication 

26 from _typeshed.wsgi import WSGIEnvironment 

27 

28 

29class Request(_SansIORequest): 

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

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

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

33 requests object is read-only. 

34 

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

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

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

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

39 :attr:`charset`. 

40 

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

42 contains information about the server configuration and client 

43 request. 

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

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

46 debugging. 

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

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

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

50 it unavailable to the final application. 

51 

52 .. versionchanged:: 2.1 

53 Remove the ``disable_data_descriptor`` attribute. 

54 

55 .. versionchanged:: 2.0 

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

57 class. Using the old classes is deprecated and will be removed 

58 in Werkzeug 2.1. 

59 

60 .. versionchanged:: 0.5 

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

62 """ 

63 

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

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

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

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

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

69 #: 

70 #: Have a look at :doc:`/request_data` for more details. 

71 #: 

72 #: .. versionadded:: 0.5 

73 max_content_length: t.Optional[int] = None 

74 

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

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

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

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

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

80 #: 

81 #: Have a look at :doc:`/request_data` for more details. 

82 #: 

83 #: .. versionadded:: 0.5 

84 max_form_memory_size: t.Optional[int] = None 

85 

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

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

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

89 #: 

90 #: .. versionadded:: 2.2.3 

91 max_form_parts = 1000 

92 

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

94 #: the form date parsing. 

95 form_data_parser_class: t.Type[FormDataParser] = FormDataParser 

96 

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

98 #: the WSGI server. 

99 environ: "WSGIEnvironment" 

100 

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

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

103 #: prevent modifying the stream from middleware. 

104 shallow: bool 

105 

106 def __init__( 

107 self, 

108 environ: "WSGIEnvironment", 

109 populate_request: bool = True, 

110 shallow: bool = False, 

111 ) -> None: 

112 super().__init__( 

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

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

115 server=_get_server(environ), 

116 root_path=_wsgi_decoding_dance( 

117 environ.get("SCRIPT_NAME") or "", self.charset, self.encoding_errors 

118 ), 

119 path=_wsgi_decoding_dance( 

120 environ.get("PATH_INFO") or "", self.charset, self.encoding_errors 

121 ), 

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

123 headers=EnvironHeaders(environ), 

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

125 ) 

126 self.environ = environ 

127 self.shallow = shallow 

128 

129 if populate_request and not shallow: 

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

131 

132 @classmethod 

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

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

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

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

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

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

139 support for cookies etc. 

140 

141 This accepts the same options as the 

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

143 

144 .. versionchanged:: 0.5 

145 This method now accepts the same arguments as 

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

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

148 

149 :return: request object 

150 """ 

151 from ..test import EnvironBuilder 

152 

153 charset = kwargs.pop("charset", cls.charset) 

154 kwargs["charset"] = charset 

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

156 try: 

157 return builder.get_request(cls) 

158 finally: 

159 builder.close() 

160 

161 @classmethod 

162 def application( 

163 cls, f: t.Callable[["Request"], "WSGIApplication"] 

164 ) -> "WSGIApplication": 

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

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

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

168 last argument and the request object will be closed 

169 automatically:: 

170 

171 @Request.application 

172 def my_wsgi_app(request): 

173 return Response('Hello World!') 

174 

175 As of Werkzeug 0.14 HTTP exceptions are automatically caught and 

176 converted to responses instead of failing. 

177 

178 :param f: the WSGI callable to decorate 

179 :return: a new WSGI callable 

180 """ 

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

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

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

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

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

186 #: partially applied functions. 

187 from ..exceptions import HTTPException 

188 

189 @functools.wraps(f) 

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

191 request = cls(args[-2]) 

192 with request: 

193 try: 

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

195 except HTTPException as e: 

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

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

198 

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

200 

201 def _get_file_stream( 

202 self, 

203 total_content_length: t.Optional[int], 

204 content_type: t.Optional[str], 

205 filename: t.Optional[str] = None, 

206 content_length: t.Optional[int] = None, 

207 ) -> t.IO[bytes]: 

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

209 

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

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

212 

213 The default implementation returns a temporary file if the total 

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

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

216 length matters. 

217 

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

219 data in the request combined. This value 

220 is guaranteed to be there. 

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

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

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

224 not provided because webbrowsers do not provide 

225 this value. 

226 """ 

227 return default_stream_factory( 

228 total_content_length=total_content_length, 

229 filename=filename, 

230 content_type=content_type, 

231 content_length=content_length, 

232 ) 

233 

234 @property 

235 def want_form_data_parsed(self) -> bool: 

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

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

238 

239 .. versionadded:: 0.8 

240 """ 

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

242 

243 def make_form_data_parser(self) -> FormDataParser: 

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

245 :attr:`form_data_parser_class` with some parameters. 

246 

247 .. versionadded:: 0.8 

248 """ 

249 return self.form_data_parser_class( 

250 self._get_file_stream, 

251 self.charset, 

252 self.encoding_errors, 

253 self.max_form_memory_size, 

254 self.max_content_length, 

255 self.parameter_storage_class, 

256 max_form_parts=self.max_form_parts, 

257 ) 

258 

259 def _load_form_data(self) -> None: 

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

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

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

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

264 force the parsing of the form data. 

265 

266 .. versionadded:: 0.8 

267 """ 

268 # abort early if we have already consumed the stream 

269 if "form" in self.__dict__: 

270 return 

271 

272 if self.want_form_data_parsed: 

273 parser = self.make_form_data_parser() 

274 data = parser.parse( 

275 self._get_stream_for_parsing(), 

276 self.mimetype, 

277 self.content_length, 

278 self.mimetype_params, 

279 ) 

280 else: 

281 data = ( 

282 self.stream, 

283 self.parameter_storage_class(), 

284 self.parameter_storage_class(), 

285 ) 

286 

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

288 # our cached_property non-data descriptor. 

289 d = self.__dict__ 

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

291 

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

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

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

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

296 

297 .. versionadded:: 0.9.3 

298 """ 

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

300 if cached_data is not None: 

301 return BytesIO(cached_data) 

302 return self.stream 

303 

304 def close(self) -> None: 

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

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

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

308 

309 .. versionadded:: 0.9 

310 """ 

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

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

313 value.close() 

314 

315 def __enter__(self) -> "Request": 

316 return self 

317 

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

319 self.close() 

320 

321 @cached_property 

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

323 """ 

324 If the incoming form data was not encoded with a known mimetype 

325 the data is stored unmodified in this stream for consumption. Most 

326 of the time it is a better idea to use :attr:`data` which will give 

327 you that data as a string. The stream only returns the data once. 

328 

329 Unlike :attr:`input_stream` this stream is properly guarded that you 

330 can't accidentally read past the length of the input. Werkzeug will 

331 internally always refer to this stream to read data which makes it 

332 possible to wrap this object with a stream that does filtering. 

333 

334 .. versionchanged:: 0.9 

335 This stream is now always available but might be consumed by the 

336 form parser later on. Previously the stream was only set if no 

337 parsing happened. 

338 """ 

339 if self.shallow: 

340 raise RuntimeError( 

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

342 " from the input stream is disabled." 

343 ) 

344 

345 return get_input_stream(self.environ) 

346 

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

348 "wsgi.input", 

349 doc="""The WSGI input stream. 

350 

351 In general it's a bad idea to use this one because you can 

352 easily read past the boundary. Use the :attr:`stream` 

353 instead.""", 

354 ) 

355 

356 @cached_property 

357 def data(self) -> bytes: 

358 """ 

359 Contains the incoming request data as string in case it came with 

360 a mimetype Werkzeug does not handle. 

361 """ 

362 return self.get_data(parse_form_data=True) 

363 

364 @typing.overload 

365 def get_data( # type: ignore 

366 self, 

367 cache: bool = True, 

368 as_text: "te.Literal[False]" = False, 

369 parse_form_data: bool = False, 

370 ) -> bytes: 

371 ... 

372 

373 @typing.overload 

374 def get_data( 

375 self, 

376 cache: bool = True, 

377 as_text: "te.Literal[True]" = ..., 

378 parse_form_data: bool = False, 

379 ) -> str: 

380 ... 

381 

382 def get_data( 

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

384 ) -> t.Union[bytes, str]: 

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

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

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

388 

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

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

391 to cause memory problems on the server. 

392 

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

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

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

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

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

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

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

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

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

402 to avoid exhausting server memory. 

403 

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

405 string. 

406 

407 .. versionadded:: 0.9 

408 """ 

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

410 if rv is None: 

411 if parse_form_data: 

412 self._load_form_data() 

413 rv = self.stream.read() 

414 if cache: 

415 self._cached_data = rv 

416 if as_text: 

417 rv = rv.decode(self.charset, self.encoding_errors) 

418 return rv 

419 

420 @cached_property 

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

422 """The form parameters. By default an 

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

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

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

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

427 

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

429 in the :attr:`files` attribute. 

430 

431 .. versionchanged:: 0.9 

432 

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

434 and PUT requests. 

435 """ 

436 self._load_form_data() 

437 return self.form 

438 

439 @cached_property 

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

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

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

443 

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

445 

446 .. versionchanged:: 2.0 

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

448 """ 

449 sources = [self.args] 

450 

451 if self.method != "GET": 

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

453 # might not treat that differently than a normal GET 

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

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

456 sources.append(self.form) 

457 

458 args = [] 

459 

460 for d in sources: 

461 if not isinstance(d, MultiDict): 

462 d = MultiDict(d) 

463 

464 args.append(d) 

465 

466 return CombinedMultiDict(args) 

467 

468 @cached_property 

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

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

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

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

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

474 

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

476 with the difference that it also has a 

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

478 store the file on the filesystem. 

479 

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

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

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

483 

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

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

486 more details about the used data structure. 

487 """ 

488 self._load_form_data() 

489 return self.files 

490 

491 @property 

492 def script_root(self) -> str: 

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

494 without a trailing slash. 

495 """ 

496 return self.root_path 

497 

498 @cached_property 

499 def url_root(self) -> str: 

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

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

502 """ 

503 return self.root_url 

504 

505 remote_user = environ_property[str]( 

506 "REMOTE_USER", 

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

508 script is protected, this attribute contains the username the 

509 user has authenticated as.""", 

510 ) 

511 is_multithread = environ_property[bool]( 

512 "wsgi.multithread", 

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

514 multithreaded WSGI server.""", 

515 ) 

516 is_multiprocess = environ_property[bool]( 

517 "wsgi.multiprocess", 

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

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

520 ) 

521 is_run_once = environ_property[bool]( 

522 "wsgi.run_once", 

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

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

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

526 happens one time.""", 

527 ) 

528 

529 # JSON 

530 

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

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

533 json_module = json 

534 

535 @property 

536 def json(self) -> t.Optional[t.Any]: 

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

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

539 

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

541 

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

543 will raise a 400 Bad Request error. 

544 

545 .. versionchanged:: 2.1 

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

547 """ 

548 return self.get_json() 

549 

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

551 # with sentinel values. 

552 _cached_json: t.Tuple[t.Any, t.Any] = (Ellipsis, Ellipsis) 

553 

554 @t.overload 

555 def get_json( 

556 self, force: bool = ..., silent: "te.Literal[False]" = ..., cache: bool = ... 

557 ) -> t.Any: 

558 ... 

559 

560 @t.overload 

561 def get_json( 

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

563 ) -> t.Optional[t.Any]: 

564 ... 

565 

566 def get_json( 

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

568 ) -> t.Optional[t.Any]: 

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

570 

571 If the mimetype does not indicate JSON 

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

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

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

575 raises a 400 Bad Request error. 

576 

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

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

579 return ``None`` instead. 

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

581 calls. 

582 

583 .. versionchanged:: 2.1 

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

585 """ 

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

587 return self._cached_json[silent] 

588 

589 if not (force or self.is_json): 

590 if not silent: 

591 return self.on_json_loading_failed(None) 

592 else: 

593 return None 

594 

595 data = self.get_data(cache=cache) 

596 

597 try: 

598 rv = self.json_module.loads(data) 

599 except ValueError as e: 

600 if silent: 

601 rv = None 

602 

603 if cache: 

604 normal_rv, _ = self._cached_json 

605 self._cached_json = (normal_rv, rv) 

606 else: 

607 rv = self.on_json_loading_failed(e) 

608 

609 if cache: 

610 _, silent_rv = self._cached_json 

611 self._cached_json = (rv, silent_rv) 

612 else: 

613 if cache: 

614 self._cached_json = (rv, rv) 

615 

616 return rv 

617 

618 def on_json_loading_failed(self, e: t.Optional[ValueError]) -> t.Any: 

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

620 

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

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

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

624 

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

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

627 """ 

628 if e is not None: 

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

630 

631 raise BadRequest( 

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

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

634 )