Brian Barbieri
Brian Barbieri

Reputation: 278

Change image source from another drive with an ajax call to flask

I want to change an image when I click on it with an image from another drive. For this I created this python function:

@main.route('/tester/', methods=['GET', 'POST'])
def tester():
    if request.method == "GET":
        test_img = "D:\TBV_Data\MS_CO_Front_20120403_140154_0001140_006.png"
        return send_file(test_img, mimetype='image/png')  

I request this data by the following function:

function testFunc() {
    $.ajax({
        url: '/tester', //server url
        type: 'GET',    //passing data as post method
        async: false,
        success: function(data) {
            $("#myimage9").attr("src", "data:image/png;base64," + data);
        },
    });
};

The outcome of the "src" of the image is, unfortunately, a load of weird data:

<img id="myimage9" src="data:image/png;base64,�PNG
IHDR�I!�IDATx���׮mK�&amp;�}�;��morg��c�V��)C�� B��.�(z�� ��� ��*��B�y2�I��^~��]D�1��ÁDb�9��&amp;�E����o-���OZl��/_���NJ��%�%�т���6�ݴw�~��EE���-�[p�z^3Y����8��#�

I can imagine that I didn't encode the image correctly. Could somebody please tell me what I am doing wrong?

EDIT: I tried to encode the data to base64 with:

function utoa(str) {
    return window.btoa(unescape(encodeURIComponent(str)));
};

This will unfortunately just changes the data to the following, but will not show the image:

<img id="myimage9" src="data:image/png;base64,/VBORw0KGgoAAAANSUhEUgAABRAAAAP9CAIAAAAUSSH9AAEAAElEQVR4/f397m1L/Sb9ff0OO/39bW9yZ/39Y/0dVv39KUP9/SBC/f0u/Sh6A

Upvotes: 1

Views: 742

Answers (2)

Tomalak
Tomalak

Reputation: 338148

On the server side, add a filename variable to your route:

import os
from flask import request, send_from_directory

IMAGE_DIR = r"D:\TBV_Data"

@main.route('/tester/<filename>')
def tester(filename):
    return send_from_directory(IMAGE_DIR, filename)

This uses the send_from_directory function to make sure that the client cannot download files from outside the designated directory by entering filenames that contain things like \..\ (this is known as "directory traversal attack").

And on the client side:

function testFunc(selector, filename) {
    $(selector).attr("src", "/tester/" + encodeURIComponent(filename) );
}

The use of encodeURIComponent() is good style and prevents problems with filenames that contain special characters. The browser will request the image as soon as its src attribute changes, there is no need to do anything via Ajax here.


Preventing a directory traversal attack with send_file() alone is a bit more involved:

filepath = os.path.realpath(os.path.join(IMAGE_DIR, filename))
if os.path.commonprefix([filepath, IMAGE_DIR]) != IMAGE_DIR:
    abort(404)

return send_file(filepath)

File paths on Windows are case-insensitive, so IMAGE_DIR should contain the actual case of the path, otherwise this test will fail.

Upvotes: 1

Brian Barbieri
Brian Barbieri

Reputation: 278

Solved:

function testFunc(args) {
        selector = args.data[0];
        filename = args.data[1];
        var obj = JSON.stringify({"data" : filename});
        console.log(obj);
        $.ajax({
            url: '/tester2/', //server url
            type: 'GET',    //passing data as post method
            data: obj,
            async: false,
            success: function(data) {
                $(selector).attr("src", "/tester2/");
            },
        });
    }; 

I was assigning the raw data to the src attribute, but I needed to assign the URL of the GET request to the src attribute.

Upvotes: 0

Related Questions