Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/flask/wrappers.py: 51%

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

85 statements  

1from __future__ import annotations 

2 

3import typing as t 

4 

5from werkzeug.exceptions import BadRequest 

6from werkzeug.exceptions import HTTPException 

7from werkzeug.wrappers import Request as RequestBase 

8from werkzeug.wrappers import Response as ResponseBase 

9 

10from . import json 

11from .globals import current_app 

12from .helpers import _split_blueprint_path 

13 

14if t.TYPE_CHECKING: # pragma: no cover 

15 from werkzeug.routing import Rule 

16 

17 

18class Request(RequestBase): 

19 """The request object used by default in Flask. Remembers the 

20 matched endpoint and view arguments. 

21 

22 It is what ends up as :class:`~flask.request`. If you want to replace 

23 the request object used you can subclass this and set 

24 :attr:`~flask.Flask.request_class` to your subclass. 

25 

26 The request object is a :class:`~werkzeug.wrappers.Request` subclass and 

27 provides all of the attributes Werkzeug defines plus a few Flask 

28 specific ones. 

29 """ 

30 

31 json_module: t.Any = json 

32 

33 #: The internal URL rule that matched the request. This can be 

34 #: useful to inspect which methods are allowed for the URL from 

35 #: a before/after handler (``request.url_rule.methods``) etc. 

36 #: Though if the request's method was invalid for the URL rule, 

37 #: the valid list is available in ``routing_exception.valid_methods`` 

38 #: instead (an attribute of the Werkzeug exception 

39 #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) 

40 #: because the request was never internally bound. 

41 #: 

42 #: .. versionadded:: 0.6 

43 url_rule: Rule | None = None 

44 

45 #: A dict of view arguments that matched the request. If an exception 

46 #: happened when matching, this will be ``None``. 

47 view_args: dict[str, t.Any] | None = None 

48 

49 #: If matching the URL failed, this is the exception that will be 

50 #: raised / was raised as part of the request handling. This is 

51 #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or 

52 #: something similar. 

53 routing_exception: HTTPException | None = None 

54 

55 _max_content_length: int | None = None 

56 _max_form_memory_size: int | None = None 

57 _max_form_parts: int | None = None 

58 

59 @property 

60 def max_content_length(self) -> int | None: 

61 """The maximum number of bytes that will be read during this request. If 

62 this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` 

63 error is raised. If it is set to ``None``, no limit is enforced at the 

64 Flask application level. However, if it is ``None`` and the request has 

65 no ``Content-Length`` header and the WSGI server does not indicate that 

66 it terminates the stream, then no data is read to avoid an infinite 

67 stream. 

68 

69 Each request defaults to the :data:`MAX_CONTENT_LENGTH` config, which 

70 defaults to ``None``. It can be set on a specific ``request`` to apply 

71 the limit to that specific view. This should be set appropriately based 

72 on an application's or view's specific needs. 

73 

74 .. versionchanged:: 3.1 

75 This can be set per-request. 

76 

77 .. versionchanged:: 0.6 

78 This is configurable through Flask config. 

79 """ 

80 if self._max_content_length is not None: 

81 return self._max_content_length 

82 

83 if not current_app: 

84 return super().max_content_length 

85 

86 return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] 

87 

88 @max_content_length.setter 

89 def max_content_length(self, value: int | None) -> None: 

90 self._max_content_length = value 

91 

92 @property 

93 def max_form_memory_size(self) -> int | None: 

94 """The maximum size in bytes any non-file form field may be in a 

95 ``multipart/form-data`` body. If this limit is exceeded, a 413 

96 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it 

97 is set to ``None``, no limit is enforced at the Flask application level. 

98 

99 Each request defaults to the :data:`MAX_FORM_MEMORY_SIZE` config, which 

100 defaults to ``500_000``. It can be set on a specific ``request`` to 

101 apply the limit to that specific view. This should be set appropriately 

102 based on an application's or view's specific needs. 

103 

104 .. versionchanged:: 3.1 

105 This is configurable through Flask config. 

106 """ 

107 if self._max_form_memory_size is not None: 

108 return self._max_form_memory_size 

109 

110 if not current_app: 

111 return super().max_form_memory_size 

112 

113 return current_app.config["MAX_FORM_MEMORY_SIZE"] # type: ignore[no-any-return] 

114 

115 @max_form_memory_size.setter 

116 def max_form_memory_size(self, value: int | None) -> None: 

117 self._max_form_memory_size = value 

118 

119 @property # type: ignore[override] 

120 def max_form_parts(self) -> int | None: 

121 """The maximum number of fields that may be present in a 

122 ``multipart/form-data`` body. If this limit is exceeded, a 413 

123 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it 

124 is set to ``None``, no limit is enforced at the Flask application level. 

125 

126 Each request defaults to the :data:`MAX_FORM_PARTS` config, which 

127 defaults to ``1_000``. It can be set on a specific ``request`` to apply 

128 the limit to that specific view. This should be set appropriately based 

129 on an application's or view's specific needs. 

130 

131 .. versionchanged:: 3.1 

132 This is configurable through Flask config. 

133 """ 

134 if self._max_form_parts is not None: 

135 return self._max_form_parts 

136 

137 if not current_app: 

138 return super().max_form_parts 

139 

140 return current_app.config["MAX_FORM_PARTS"] # type: ignore[no-any-return] 

141 

142 @max_form_parts.setter 

143 def max_form_parts(self, value: int | None) -> None: 

144 self._max_form_parts = value 

145 

146 @property 

147 def endpoint(self) -> str | None: 

148 """The endpoint that matched the request URL. 

149 

150 This will be ``None`` if matching failed or has not been 

151 performed yet. 

152 

153 This in combination with :attr:`view_args` can be used to 

154 reconstruct the same URL or a modified URL. 

155 """ 

156 if self.url_rule is not None: 

157 return self.url_rule.endpoint # type: ignore[no-any-return] 

158 

159 return None 

160 

161 @property 

162 def blueprint(self) -> str | None: 

163 """The registered name of the current blueprint. 

164 

165 This will be ``None`` if the endpoint is not part of a 

166 blueprint, or if URL matching failed or has not been performed 

167 yet. 

168 

169 This does not necessarily match the name the blueprint was 

170 created with. It may have been nested, or registered with a 

171 different name. 

172 """ 

173 endpoint = self.endpoint 

174 

175 if endpoint is not None and "." in endpoint: 

176 return endpoint.rpartition(".")[0] 

177 

178 return None 

179 

180 @property 

181 def blueprints(self) -> list[str]: 

182 """The registered names of the current blueprint upwards through 

183 parent blueprints. 

184 

185 This will be an empty list if there is no current blueprint, or 

186 if URL matching failed. 

187 

188 .. versionadded:: 2.0.1 

189 """ 

190 name = self.blueprint 

191 

192 if name is None: 

193 return [] 

194 

195 return _split_blueprint_path(name) 

196 

197 def _load_form_data(self) -> None: 

198 super()._load_form_data() 

199 

200 # In debug mode we're replacing the files multidict with an ad-hoc 

201 # subclass that raises a different error for key errors. 

202 if ( 

203 current_app 

204 and current_app.debug 

205 and self.mimetype != "multipart/form-data" 

206 and not self.files 

207 ): 

208 from .debughelpers import attach_enctype_error_multidict 

209 

210 attach_enctype_error_multidict(self) 

211 

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

213 try: 

214 return super().on_json_loading_failed(e) 

215 except BadRequest as ebr: 

216 if current_app and current_app.debug: 

217 raise 

218 

219 raise BadRequest() from ebr 

220 

221 

222class Response(ResponseBase): 

223 """The response object that is used by default in Flask. Works like the 

224 response object from Werkzeug but is set to have an HTML mimetype by 

225 default. Quite often you don't have to create this object yourself because 

226 :meth:`~flask.Flask.make_response` will take care of that for you. 

227 

228 If you want to replace the response object used you can subclass this and 

229 set :attr:`~flask.Flask.response_class` to your subclass. 

230 

231 .. versionchanged:: 1.0 

232 JSON support is added to the response, like the request. This is useful 

233 when testing to get the test client response data as JSON. 

234 

235 .. versionchanged:: 1.0 

236 

237 Added :attr:`max_cookie_size`. 

238 """ 

239 

240 default_mimetype: str | None = "text/html" 

241 

242 json_module = json 

243 

244 autocorrect_location_header = False 

245 

246 @property 

247 def max_cookie_size(self) -> int: # type: ignore 

248 """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. 

249 

250 See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in 

251 Werkzeug's docs. 

252 """ 

253 if current_app: 

254 return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] 

255 

256 # return Werkzeug's default when not in an app context 

257 return super().max_cookie_size