0

I'm writing a small Flask program, which involves a user uploading PDF files via an html/javascript form in the frontend, which are processed together in the backend.

Testing on Ubuntu and Android (Firefox) I have no problems. I asked two other users to test (one using iphone, the other using Windows) and the upload for both seems to be failing.

Frontend extracts

        <form id="bundleForm" action="/create_bundle" method="POST" enctype="multipart/form-data">
        <div class="card">
                <div class="card-header">
                    <div class="card-icon">
                        <i class="mdi mdi-file-multiple"></i>
                    </div>
                    <h2 class="card-title">Add PDFs</h2>
                </div>
                <div id="dropZone" class="upload-zone">
                    <i class="mdi mdi-upload upload-icon" style="color: #d57782;"></i>
                    <p><span style="color: #d57782; font-size: 1.2rem;"><b>Upload your PDFs here:</b> Click to select, or drag and drop</p></span>
                    <input type="file" id="fileInput" name="files" multiple accept=".pdf" style="display: none;">
                    <div class="progress-container">
                        <div class="progress-bar"></div>
                    </div>
                </div>
          </div>`

Backend upload handling extracts


def save_uploaded_file(file, directory, filename=None):
    app.logger.debug(f"[{session_id}-{timestamp}-APP]-- save_uploaded_files activated for {file}")
    if file and file.filename:
        filename = filename or file.filename
        filename = secure_filename(filename)
        filepath = os.path.join(directory, filename)
        file.save(filepath)
        return filepath
    return None

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/create', methods=['GET', 'POST'])
def create():
    if request.method == 'GET':
        return render_template('index.html')

    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    session_id = str(uuid.uuid4())[:8]
    try:
        # Create temporary working directory in ./tempfiles/{timestamp}:
        if not os.path.exists('tempfiles'):
            os.makedirs('tempfiles')
        temp_dir = os.path.join('tempfiles', session_id)
        os.makedirs(temp_dir)
        app.logger.debug(f"[{session_id}-{timestamp}-APP]-- Temporary directory created: {temp_dir}")
        
        # Save uploaded files
        app.logger.debug(f"[{session_id}-{timestamp}-APP]-- ******************Gathering uploads******************")
        files = secure_filename(request.files.getlist('files'))
        input_files = []
        for file in files:
            if file.filename:
                filepath = save_uploaded_file(file, temp_dir)
                if filepath:
                    input_files.append(filepath)
        app.logger.debug(f"[{session_id}-{timestamp}-APP]-- Number of input_files: {len(input_files)}")

[...etc]

Serving and other info.

The app's being served with Waitress with a default configuration. The test was done on an environment without adding any explicit limits to file size and without changing the default timeout settings.

I don't think it's a permissions issue, because successful tests were run on the same instance as the tests which failed. I don't think it's a filename issue, because the filenames are being sanitised.

The debug logging was an attempt to root out the problem, without success. I've personally tested on Android and Ubuntu, in each case on the local network and remotely, and in each case with different browsers but could not replicate.

When I test directly, I am getting a debug message with the correct number of inputs - for example, Number of input_files: 3. However, in other tests it is logging as Number of input_files: 0.

One user reported that it seems to ignore the first file they upload, but (sometimes?) handles the remaining files.

Other SO answers I've found suggest tweaks that don't seem to affect the problem, and don't explain why it would vary with different user setups. Otherwise, this being my first time using javascript or Flask, I'm not at all sure where to begin.

1
  • It seems to me that there is an error in the line files = secure_filename(request.files.getlist('files')), because request.files.getlist(key) returns a list of FileStorage objects and the attribute for secure_filename(filename) is expected to be a file name as a string. This should result in an error message, regardless of the system. Commented Jan 6 at 13:54

1 Answer 1

0

Maybe some hints to check that may help you debug the problem.

  • Are you checking in the front before sending the data that the files are correctly added to the form before sending them ? you can use an eventListener for the submit for example
  • use are using: files = secure_filename(request.files.getlist('files')). I'm not a Flask specialist, more of a django user I would say, but when checking the documentation, wouldn't be wrong to use secure_filename on a list of files ? and shouldn't be used only on filename ?
  • One last point that may cause some troubles, it's the dropzone input, which surely relay on Javascript. You can maybe check that the files are correctly uploaded to the form. Which join somehow the first point.

I hope it may help a little bit

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for these useful observations. These are good points that I'll explore. I have fixed the second of them already.
you're welcome @TrisSherliker, Hope it will help. Don't hesitate to throw a thumb up if it did. Good luck
Done! I found the error: it was not at all in the excerpt I posted, but your comments helped lead me there. Thanks again.
you're welcome ! Happy to help :D. So out of curiosity, what was the exact problem ?
It's a little bit embarrassing. The exact problem was how users were interacting with the form: the form has two upload paths, a select-files-on-click path as well as a drag-and-drop upload zone. The bug was in the Drag-and-Drop Zone file handling. I'd overlooked it though because I hate drag and drop so had forgotten to test it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.