The most important rule about web development is “Do not trust the user”. This is especially true for incoming request data on the input stream. With WSGI this is actually a bit harder than you would expect. Because of that Werkzeug wraps the request stream for you to save you from the most prominent problems with it.
The input stream has no end-of-file marker. If you would call the read()
method on the wsgi.input
stream you would cause your application to hang on conforming servers. This is actually intentional however painful. Werkzeug solves that problem by wrapping the input stream in a special LimitedStream
. The input stream is exposed on the request objects as stream
. This one is either an empty stream (if the form data was parsed) or a limited stream with the contents of the input stream.
Werkzeug parses the incoming data under the following situations:
form
, files
, or stream
and the request method was POST
or PUT
.parse_form_data()
.These calls are not interchangeable. If you invoke parse_form_data()
you must not use the request object or at least not the attributes that trigger the parsing process.
This is also true if you read from the wsgi.input
stream before the parsing.
General rule: Leave the WSGI input stream alone. Especially in WSGI middlewares. Use either the parsing functions or the request object. Do not mix multiple WSGI utility libraries for form data parsing or anything else that works on the input stream.
The standard Werkzeug parsing behavior handles three cases:
multipart/form-data
. In this situation the stream
will be empty and form
will contain the regular POST
/ PUT
data, files
will contain the uploaded files as FileStorage
objects.application/x-www-form-urlencoded
. Then the stream
will be empty and form
will contain the regular POST
/ PUT
data and files
will be empty.stream
points to a LimitedStream
with the input data for further processing.Special note on the get_data
method: Calling this loads the full request data into memory. This is only safe to do if the max_content_length
is set. Also you can either read the stream or call get_data()
.
To avoid being the victim of a DDOS attack you can set the maximum accepted content length and request field sizes. The BaseRequest
class has two attributes for that: max_content_length
and max_form_memory_size
.
The first one can be used to limit the total content length. For example by setting it to 1024 * 1024 * 16
the request won’t accept more than 16MB of transmitted data.
Because certain data can’t be moved to the hard disk (regular post data) whereas temporary files can, there is a second limit you can set. The max_form_memory_size
limits the size of POST
transmitted form data. By setting it to 1024 * 1024 * 2
you can make sure that all in memory-stored fields are not more than 2MB in size.
This however does not affect in-memory stored files if the stream_factory
used returns a in-memory file.
Modern web applications transmit a lot more than multipart form data or url encoded data. To extend the capabilities, subclass BaseRequest
or Request
and add or extend methods.
There is already a mixin that provides JSON parsing:
from werkzeug.wrappers import Request from werkzeug.wrappers.json import JSONMixin class JSONRequest(JSONMixin, Request): pass
The basic implementation of that looks like:
from werkzeug.utils import cached_property from werkzeug.wrappers import Request import simplejson as json class JSONRequest(Request): @cached_property def json(self): if self.mimetype == "application/json": return json.loads(self.data)
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://werkzeug.palletsprojects.com/en/1.0.x/request_data/