Skip to content

No per-IP concurrency limit on /convert, parallel uploads exhaust Pillow threads (DoS) #572

Description

@anshul23102

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

  1. 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))))
  1. 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()

Metadata

Metadata

Assignees

Labels

GSSoCOpen Source EventenhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions