ploneasgi.vhm#

Read VirtualHostMonster rewrites at the ASGI layer.

Native routes are siblings of the Zope mount, which puts them on the wrong side of the proxy: a deployment already rewrites every request into

/VirtualHostBase/<protocol>/<host:port>/<site-path>/VirtualHostRoot/<rest>

and a route that does not understand that shape needs its own proxy rule to be reachable — one more rule per route, forever. Parsing the rewrite here instead means the existing rule serves native routes too, and no new infrastructure is needed to add one.

It also removes a duplication. The site path is already inside the rewrite (Plone above), so a route does not have to restate it in its path, and the external scheme and host are recovered as a side effect — without them a native route behind TLS termination sees http and the container's address.

The reserved prefix is what makes this unambiguous. Anything whose rewritten path starts with it belongs to a native route; everything else is Zope's, and its scope is passed through untouched so Zope's own VirtualHostMonster still sees the URL it expects. Getting that wrong would corrupt every URL Plone generates, which is why tests/test_vhm.py spends most of its length on it.

Grammar per Products.SiteAccess.VirtualHostMonster. _vh_ segments — the virtual-path-prefix feature — are deliberately not supported: they change what the root path means, and guessing wrong would silently mis-route. A request that uses them against a native route is refused loudly instead.

ploneasgi.vhm.DEFAULT_PREFIX = '/++asgi++'#

Path prefix reserved for native ASGI routes. Chosen to match Zope's ++namespace++ traversal convention, which content ids cannot collide with.

ploneasgi.vhm.SITE_KEY = 'ploneasgi.site'#

Key under which the path to the virtual root is placed on the ASGI scope.

ploneasgi.vhm.RAW_PATH_SAFE = "/:@!$&'()*+,;="#

Characters left unquoted in raw_path: RFC 3986 pchar minus %, plus the / separator.

ploneasgi.vhm.REWRITTEN_KEY = 'ploneasgi.vhm'#

Key marking that a scope was rewritten, so downstream code can tell a proxied request from a direct one.

class ploneasgi.vhm.VirtualHost[source]#

A parsed VirtualHostMonster rewrite.

Variables:
  • protocol -- External scheme, e.g. https.

  • host -- External host, without the port.

  • port -- External port, or None when the URL carried none.

  • site -- Path from the Zope root to the virtual root, e.g. Plone or sites/Plone/folder — everything before VirtualHostRoot. It names an object inside a site, not necessarily the site itself; ploneasgi.context.run_authenticated() finds the site by walking it.

  • path -- The real request path, after VirtualHostRoot.

  • has_vh_segments -- Whether _vh_ prefix segments were present.

__init__(protocol, host, port, site, path, has_vh_segments=False)#
Parameters:
Return type:

None

ploneasgi.vhm.parse_virtual_host(path)[source]#

Parse a VirtualHostMonster-rewritten path.

Parameters:

path (str) -- The raw request path.

Returns:

The parsed rewrite, or None when the path is not one.

Return type:

VirtualHost | None

class ploneasgi.vhm.VirtualHostMiddleware[source]#

Route VirtualHostMonster-rewritten requests to native ASGI routes.

Variables:
  • prefix -- Reserved path prefix identifying a native route.

  • default_site -- Site id used when a request arrives without a rewrite, which is the direct-access case in development.

__init__(app, *, prefix='/++asgi++', default_site=None)[source]#
Parameters:
Return type:

None