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.
files = secure_filename(request.files.getlist('files')), becauserequest.files.getlist(key)returns a list ofFileStorageobjects and the attribute forsecure_filename(filename)is expected to be a file name as a string. This should result in an error message, regardless of the system.