0

I used flask and flask-restplus to generate an upload api endpoint for my application. All seems working fine, but files data received are empty and then the saved file is empty.

Here is my code

upload_parser = reqparse.RequestParser()
upload_parser.add_argument('data', location='files', type=FileStorage, required=True)
 ...

@ns.route('/upload')
class Upload(Resource):

    @api.expect(upload_parser)
    def post(self):
        args = upload_parser.parse_args()
        uploaded_file = args['data']  # This is FileStorage instance
        scan_for_virus(uploaded_file)  # This function raised error if a virus are found
        destination = current_app.config.get('UPLOAD_DATA_FOLDER')
        if not os.path.exists(destination):
            os.makedirs(destination)
        temp_filename = os.path.join(destination, str(uuid.uuid4()))

        print uploaded_file  # print "<FileStorage: u'IMG-20190129-WA0001.jpg' ('image/jpeg')>" seems correct
        print uploaded_file.stream  # print "<tempfile.SpooledTemporaryFile instance at 0x104b1c3f8>}"
        print uploaded_file.content_length  # print "0" ..... but my orignal file size is 4352436 bytes
        uploaded_file.save(temp_filename)  # create the file with the correct path, but this new file is empty.
        return {'url': 'upload://{0}'.format(os.path.basename(temp_filename))}, 202

I use a swagger interface (generated by restplus framework) tu upload the file. The sent request are :

curl -X POST "http://localhost:8888/api/upload" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "data=@my_file.pdf;type=application/pdf"

Do you have any suggestions to solve my problem ? Does I need to specify something special into my flask configuration ? Thanks for your help

Renaud

Renaud Michotte
  • 389
  • 4
  • 17

1 Answers1

0

Ok, I find the problem.... The problem was into my scan_for_virus function:

def scan_for_virus(uploaded_file):
    try:
        cd = pyclamd.ClamdUnixSocket(current_app.config.get('CLAMAV_SOCKET_FILE', '/tmp/clamd.socket'))
        cd.ping()
    except pyclamd.ConnectionError as ce:
        log.error("Unable to connect to Clamd :: "+str(ce))
        abort(500, str(ce))
    scan_result = cd.scan_stream(uploaded_file.stream)
    if scan_result is not None:  # In this case ClamAV found a virus !
        log.warning("Virus found into {0} :: {1}".format(uploaded_file.filename, scan_result['stream'][1]))
        abort(502, "Virus found !", detail=scan_result['stream'][1])

As you can see the scan_stream use the uploaded_file.stream attribute to read the uploaded_file content. But the FileStorage.save() function use also the stream attribute, thus I need to reset the stream after first read :

....
scan_result = cd.scan_stream(uploaded_file.stream)
uploaded_file.stream.seek(0)
....

Just doing that, it works as expected.

Renaud Michotte
  • 389
  • 4
  • 17