aboutsummaryrefslogtreecommitdiffstats
path: root/python/werkzeug/middleware/dispatcher.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/werkzeug/middleware/dispatcher.py')
-rw-r--r--python/werkzeug/middleware/dispatcher.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/python/werkzeug/middleware/dispatcher.py b/python/werkzeug/middleware/dispatcher.py
new file mode 100644
index 0000000..2eb173e
--- /dev/null
+++ b/python/werkzeug/middleware/dispatcher.py
@@ -0,0 +1,66 @@
+"""
+Application Dispatcher
+======================
+
+This middleware creates a single WSGI application that dispatches to
+multiple other WSGI applications mounted at different URL paths.
+
+A common example is writing a Single Page Application, where you have a
+backend API and a frontend written in JavaScript that does the routing
+in the browser rather than requesting different pages from the server.
+The frontend is a single HTML and JS file that should be served for any
+path besides "/api".
+
+This example dispatches to an API app under "/api", an admin app
+under "/admin", and an app that serves frontend files for all other
+requests::
+
+ app = DispatcherMiddleware(serve_frontend, {
+ '/api': api_app,
+ '/admin': admin_app,
+ })
+
+In production, you might instead handle this at the HTTP server level,
+serving files or proxying to application servers based on location. The
+API and admin apps would each be deployed with a separate WSGI server,
+and the static files would be served directly by the HTTP server.
+
+.. autoclass:: DispatcherMiddleware
+
+:copyright: 2007 Pallets
+:license: BSD-3-Clause
+"""
+
+
+class DispatcherMiddleware(object):
+ """Combine multiple applications as a single WSGI application.
+ Requests are dispatched to an application based on the path it is
+ mounted under.
+
+ :param app: The WSGI application to dispatch to if the request
+ doesn't match a mounted path.
+ :param mounts: Maps path prefixes to applications for dispatching.
+ """
+
+ def __init__(self, app, mounts=None):
+ self.app = app
+ self.mounts = mounts or {}
+
+ def __call__(self, environ, start_response):
+ script = environ.get("PATH_INFO", "")
+ path_info = ""
+
+ while "/" in script:
+ if script in self.mounts:
+ app = self.mounts[script]
+ break
+
+ script, last_item = script.rsplit("/", 1)
+ path_info = "/%s%s" % (last_item, path_info)
+ else:
+ app = self.mounts.get(script, self.app)
+
+ original_script_name = environ.get("SCRIPT_NAME", "")
+ environ["SCRIPT_NAME"] = original_script_name + script
+ environ["PATH_INFO"] = path_info
+ return app(environ, start_response)