Create a routing middleware matching hostname, port and path.
Parameters: |
|
---|
Returns a WFront WSGI callable:
router = wfront.route([('www.my.host:80', app, None)])
Create a routing middleware matching hostname, URL scheme and path.
Parameters: |
|
---|
If you have a server that speaks HTTP on 80, 8000 and 8001, you might specify:
router = wfront.by_scheme([('www.my.host:http', app, None)],
schemes={'http': (80, 8000, 8001)})
This would match on a request for www.my.host made to port 80, 8000 or 8001.
The base implementation can be extended for custom functionality.
Create a routing middleware that directs to one or more WSGI apps.
Parameters: |
|
---|
A simple router that answers any request for localhost:
front = WFront([('localhost', myapp, None)])
A more complex router:
mapping = [ ('www.example.com', myapp),
('www.example.com:443', sec_app, 'mymodule.filter'),
('wap.example.mobi', myapp, {'mode': 'wap'}), ]
router = WFront(mapping)
By default, the requested host is taken from HTTP_HOST and guaranteed to contain a port number. You can customize this behavior by supplying ‘host_resolver’ as a function that takes the environ and returns a string of ‘hostname:port:path’
Add a new mapping.
Spec may be a regex in which case it is used as-is, otherwise spec is regex-escaped and converted into a host:port:path matcher.
If a regex is supplied and it contains a ‘pathinfo’ named group, that group will be used in PATH_INFO / SCRIPT_NAME manipulation.
In many cases, this function will ‘just work’ and retrieve the correct ‘hostname’ and ‘path’ from the environ with no fuss. If it is not working for your web server and/or WSGI container, the implementation is listed below.
path = environ.get('REQUEST_URI', None)
if path is None:
path = environ.get('SCRIPT_NAME', '') + environ.get('PATH_INFO')
# mod_proxy-style forward?
if 'HTTP_X_FORWARDED_FOR' in environ:
# Some pass it in an x-header
if 'HTTP_X_FORWARDED_HOST' in environ:
host = environ['HTTP_X_FORWARDED_HOST']
# some others pass along the original Host:
elif self.proxied_host_is_accurate and 'HTTP_HOST' in environ:
host = environ['HTTP_HOST']
# Or, default to remote server name if the client didn't
# supply Host:
elif 'HTTP_X_FORWARDED_SERVER' in environ:
host = environ['HTTP_X_FORWARDED_SERVER']
# Otherwise ignore Host: and default to our server name.
else:
host = environ['SERVER_NAME']
# In a proxy situation, the original request port is only
# known if there is a Host: or forwarded Host: header AND
# the request is either on a non-standard port or is http
# on port 80. There's no way to distinguish a
# simply-proxied HTTP and HTTPS connection! Given that,
# default to 80. Ignore wsgi.url_scheme until such a time
# as the WSGI spec makes it clear if this is variable
# describes the *user's* URL scheme or the application
# container's URL scheme. It's safer to assume the
# latter.
if ':' not in host:
host += ':' + environ.get('HTTP_X_FORWARDED_PORT', '80')
return host + ':' + path
# Not mod_proxy-style proxied- assume direct connection.
else:
host = environ.get('HTTP_HOST', None)
if host is None:
host = environ['SERVER_NAME'] + ':' + environ['SERVER_PORT']
elif ':' not in host:
ssl = environ.get('HTTPS', environ['wsgi.url_scheme']).lower()
if ssl in _ssl_flags:
host += ':443'
else:
host += ':80'
return host + ':' + path