Using SCRIPT_NAME in Flask standalone

This is a variant of the ReverseProxied solution from pocoo. As it depends on __call__ being called inside a wsgi environment, it does not work when the app is being run standalone with run().

ScriptNameHandler

We solve this by instead overriding the make_environ() function of WSGIRequestHandler inside a new class, ScriptNameHandler, and passing it as an argument to Werkzeug’s run_simple(), like so:

from werkzeug.serving import WSGIRequestHandler
class ScriptNameHandler(WSGIRequestHandler):
def make_environ(self):
environ = super().make_environ()
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '')
if scheme:
environ['wsgi.url_scheme'] = scheme
return environ
from werkzeug.serving import WSGIRequestHandler class ScriptNameHandler(WSGIRequestHandler): def make_environ(self): environ = super().make_environ() script_name = environ.get('HTTP_X_SCRIPT_NAME', '') if script_name: environ['SCRIPT_NAME'] = script_name path_info = environ['PATH_INFO'] if path_info.startswith(script_name): environ['PATH_INFO'] = path_info[len(script_name):] scheme = environ.get('HTTP_X_SCHEME', '') if scheme: environ['wsgi.url_scheme'] = scheme return environ
from werkzeug.serving import WSGIRequestHandler

class ScriptNameHandler(WSGIRequestHandler):
    def make_environ(self):
        environ = super().make_environ()
        script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
        if script_name:
            environ['SCRIPT_NAME'] = script_name
            path_info = environ['PATH_INFO']
        if path_info.startswith(script_name):
            environ['PATH_INFO'] = path_info[len(script_name):]

        scheme = environ.get('HTTP_X_SCHEME', '')
        if scheme:
            environ['wsgi.url_scheme'] = scheme
        return environ

Then change

app.run()
app.run()
app.run()

to

app.run(request_handler=ScriptNameHandler)
app.run(request_handler=ScriptNameHandler)
app.run(request_handler=ScriptNameHandler)

Passing the http header X-SCRIPT-NAME to the app creates the value HTTP_X_SCRIPT_NAME in the environ variable.

Apache example

<Location "/test_subdir">
ProxyPass "http://localhost:8081"
X-SCRIPT-NAME "/test_subdir"
</Location>
<Location "/test_subdir"> ProxyPass "http://localhost:8081" X-SCRIPT-NAME "/test_subdir" </Location>
<Location "/test_subdir">
    ProxyPass "http://localhost:8081" 
    X-SCRIPT-NAME "/test_subdir"
</Location>