I use Bottle to receive gzipped request body. When the size of the request is small, everything is fine. However, if the size of request body is a bit larger (say, >= 20kb), an IOError is thrown.
The following is the code used to read and decompress the request body:
@post("/receive")
def receive():
try:
f = request.body
g_f = gzip.GzipFile(fileobj=f)
content = g_f.read()
# other stuff on the content...
except IOError, e:
# handle the error
The error message is:
[2015-09-07 16:27:27,967][ERROR ] Failed to decompress gzipped data: [Errno 9] read() on write-only GzipFile object
127.0.0.1 - - [07/Sep/2015 16:27:27] "POST /receive HTTP/1.1" 400 756
This problem is caused by the inheritance of the read/write mode of the fileobj used to create the GzipFile
object.
If the size of the request.body
is less than 20k, Bottle
loads the whole binary data as a StringIO
object. GzipFile
deals with StringIO
very well, everything works fine.
On the other hand, if the size of the request.body
is larger than 20k, Bottle
will use tempfile
module to create a temporary file for this request body, for platform-consistency, the default mode of files created by tempfile
is 'w+b'.
However, GzipFile determines if a file readable or not only by the mode string obtained by hasattr(fileobj, 'mode')
, if this string is something like 'rxx', GzipFile
considers it as readable, and vice versa. If the read()
function of a non-readable GzipFile
is invoked, an IOError
will be thrown.
Since the mode of the file which will be used by the GzipFile
is 'w+b', the GzipFile
is still going to consider it as 'non-readable', so, boom! Error thrown. To fix this, just add the mode
argument when creating the GzipFile
object:
try:
f = request.body
g_f = gzip.GzipFile(fileobj=f, mode='rb')
content = g_f.read()
# other stuff on the content...
except IOError, e:
# handle the error