Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending a flask request within a flask request

I am implementing an endpoint in my Flask application that receives a collection of HTTP requests, and returns a collection of the corresponding HTTP responses. In order to accomplish this, I need my endpoint to call other endpoints in order to construct the result. However, because Flask is blocking while processing the original request, it cannot process the nested requests and the application gets deadlocked.

Is there any way to issue a request within a request in flask in a way that doesn't result in a deadlock?

I included a segment of my code which I believe should be enough to illustrate the problem without overwhelming you. If you would like to see more of it please let me know and I'll share.

from requests import Session, Request

def split(request):
    multipart = request.stream.read()
    boundary = request.content_type.split(';')[1]
    prefix = ' boundary"'
    suffix = '"'
    delimiter = '--%s' % boundary[len(prefix)+1:-len(suffix)]
    subrequests = [s.lstrip() for s in multipart.split(delimiter)]
    for sub in subrequests:
        status_line, _, more_lines = sub.partition('\n')
        method, path, version = status_line.split()
        headers, _, body = more_lines.partition('\n\n')
        url = 'http://localhost:3000' + path
        return Request(method, url, headers=headers, data=body)

@app.route('/batch', methods=["GET", "POST"])
def batch():
    subrequests = split(request)
    session = Session()
    responses = []
    for sub in subrequests:
        response.append(s.send(sub.prepare())) # Deadlock!

There are two candidate solutions that I considered which I found to be unsatisfactory:

  1. Don't issue a full request. Instead, just call the function that is mapped to the endpoint of interest (url_for). I am unsatisfied by this approach because the nested requests have their own headers and cookies which are neglected by this approach. Furthermore, code in the 'before_request' and 'after_request' handlers won't get called automatically

  2. Run multiple instances of the application. This will solve the problem, but expose my service to a pretty simple DoS attack. If I have X instances running, All an attacker would need to do is to hit my service with X different requests to cause a deadlock.

Thank you.

like image 452
gilsho Avatar asked Jun 03 '14 09:06

gilsho


2 Answers

Knowing that the internal flask server is not production-ready, when using only for development, pass the threaded=true parameter to app.run.

app.run(debug=True, threaded=True)
like image 70
Rangel Reale Avatar answered Sep 18 '22 08:09

Rangel Reale


This happens cause you're using the flask devserver. It's not for production use. In production environment you would use an application server (uWSGI, GUnicorn, Tornado, ...) with or without a webserver layer (NGINX, Apache,...) to proxy/balance connections to the workers protecting (not completely but in a lot of environments it's acceptable) from DoS attacks.

like image 44
Paolo Casciello Avatar answered Sep 19 '22 08:09

Paolo Casciello