I'm using tornado.web.stream_request_body
(tornado v4.0.1) to save post data but it seems like mime-type of the saved files remain as application/octet-stream
.
i need to know mime-type of the uploaded file and here is my code snippet;
@stream_request_body
class MainHandler(tornado.web.RequestHandler):
def post(self):
pass
def prepare(self):
self.temp_file = tempfile.NamedTemporaryFile(delete=False)
def data_received(self, chunk):
self.temp_file.write(chunk)
extra information;
files are saved properly using curl
with --data-binary
parameter;
curl -v -XPOST --data-binary @example.pdf localhost:8888/
but browser uploads with multipart/form-data
or curl with parameter -d
does not work.
When i look into saved file with text editor, i see http post parameters at the first lines;
-----------------------------192365691191582744435855330
Content-Disposition: form-data; name="upload"; filename="example.mp3"
Content-Type: audio/mpeg
...
unreadable binary data
any idea about this?
UPDATE: I have created a package for Python3 and Tornado 4.0+ that can be installed with PyPi: https://pypi.python.org/pypi/tornadostreamform
I know that the previous answer was already accepted, but I have had the same problem and I can provide a complete module - let's call it post_streamer - for Python 3 that will parse any stream into parts for any request, without using too much memory.
It could be a bit more efficient, but it is portable and does not load anything big into memory. Here is how you can use it, tested with tornado web 4.0, (and firefox and pycurl as the client). Just start this server and point your browser to your localhost, port 8888
After finish_receive() was called, you can access the Content-Type header using PostDataStreamer.params and PostDataStreamer.get_part_ct_param(part, "Content-Type")
UPDATE: the max_buffer_size should not be increased in general. The max_body_size should not be increased in general. They should be kept at low values. Only in the prepare() method of the handler that was decorated with stream_request_body, should we call self.request.connection.set_max_body_size() in order to set the maximum size that can be streamed. For details see: https://groups.google.com/forum/#!topic/python-tornado/izEXQd71rQk
This was an undocumented part of tornado. I'm preparing a module that can be used for handling file uploads out of the box. When ready, I'll put a link here.
In stream_request_body mode you get the raw body as uploaded by the client, without the processing that creates self.request.arguments or self.request.files. This is a multipart/form-data wrapper (not the http headers, although they do look similar); you'll need to parse this to get the filename and the embedded data. I think the mime-related tools in the standard library's email package are probably the best way to parse this once you've gotten it saved to a file.