Bug Description
The /convert endpoint applies no concurrency limit per client. Sending 50 simultaneous PDF conversion requests saturates the Flask thread pool and Pillow worker threads, causing the server to become unresponsive to other users.
Steps to Reproduce
- Run the following script:
import concurrent.futures, requests
def upload():
with open('test.pdf','rb') as f:
return requests.post('http://localhost:5000/convert',
files={'file': f}).status_code
with concurrent.futures.ThreadPoolExecutor(50) as ex:
print(list(ex.map(lambda _: upload(), range(50))))
- Observe: server CPU reaches 100% and subsequent requests time out.
Root Cause
No request queue, semaphore, or thread-pool size cap in the Flask conversion handler.
Impact
Denial of service: one script can make the service unavailable to all other users.
Proposed Fix
from threading import Semaphore
CONVERT_SEM = Semaphore(4) # max 4 concurrent conversions
@app.route('/convert', methods=['POST'])
def convert():
if not CONVERT_SEM.acquire(blocking=False):
return jsonify({'error': 'Server busy, try again later'}), 503
try:
return do_convert()
finally:
CONVERT_SEM.release()
Bug Description
The
/convertendpoint applies no concurrency limit per client. Sending 50 simultaneous PDF conversion requests saturates the Flask thread pool and Pillow worker threads, causing the server to become unresponsive to other users.Steps to Reproduce
Root Cause
No request queue, semaphore, or thread-pool size cap in the Flask conversion handler.
Impact
Denial of service: one script can make the service unavailable to all other users.
Proposed Fix