Ensure that blueprint subdomains suffix-chain

This ensures that a child's subdomain prefixs any parent subdomain
such that the full domain is child.parent.domain.tld and onwards with
further nesting. This makes the most sense to users and mimics how
url_prefixes work (although subdomains suffix).
This commit is contained in:
pgjones 2023-01-04 16:45:20 +00:00
parent d7b6c1f670
commit cabda59353
4 changed files with 26 additions and 4 deletions

View file

@ -3,6 +3,8 @@ Version 2.3.0
Unreleased Unreleased
- Ensure subdomains are applied with nested blueprints. :issue:`4834`
Version 2.2.3 Version 2.2.3
------------- -------------

View file

@ -140,6 +140,19 @@ name, and child URLs will be prefixed with the parent's URL prefix.
url_for('parent.child.create') url_for('parent.child.create')
/parent/child/create /parent/child/create
In addition a child blueprint's will gain their parent's subdomain,
with their subdomain as prefix if present i.e.
.. code-block:: python
parent = Blueprint('parent', __name__, subdomain='parent')
child = Blueprint('child', __name__, subdomain='child')
parent.register_blueprint(child)
app.register_blueprint(parent)
url_for('parent.child.create', _external=True)
"child.parent.domain.tld"
Blueprint-specific before request functions, etc. registered with the Blueprint-specific before request functions, etc. registered with the
parent will trigger for the child. If a child does not have an error parent will trigger for the child. If a child does not have an error
handler that can handle a given exception, the parent's will be tried. handler that can handle a given exception, the parent's will be tried.

View file

@ -358,6 +358,9 @@ class Blueprint(Scaffold):
:param options: Keyword arguments forwarded from :param options: Keyword arguments forwarded from
:meth:`~Flask.register_blueprint`. :meth:`~Flask.register_blueprint`.
.. versionchanged:: 2.3
Nested blueprints now correctly apply subdomains.
.. versionchanged:: 2.0.1 .. versionchanged:: 2.0.1
Nested blueprints are registered with their dotted name. Nested blueprints are registered with their dotted name.
This allows different blueprints with the same name to be This allows different blueprints with the same name to be
@ -458,10 +461,12 @@ class Blueprint(Scaffold):
if bp_subdomain is None: if bp_subdomain is None:
bp_subdomain = blueprint.subdomain bp_subdomain = blueprint.subdomain
if state.subdomain is not None and bp_subdomain is None: if state.subdomain is not None and bp_subdomain is not None:
bp_options["subdomain"] = state.subdomain bp_options["subdomain"] = bp_subdomain + "." + state.subdomain
elif bp_subdomain is not None: elif bp_subdomain is not None:
bp_options["subdomain"] = bp_subdomain bp_options["subdomain"] = bp_subdomain
elif state.subdomain is not None:
bp_options["subdomain"] = state.subdomain
if bp_url_prefix is None: if bp_url_prefix is None:
bp_url_prefix = blueprint.url_prefix bp_url_prefix = blueprint.url_prefix

View file

@ -971,7 +971,7 @@ def test_nesting_subdomains(app, client) -> None:
assert response.status_code == 200 assert response.status_code == 200
def test_child_overrides_parent_subdomain(app, client) -> None: def test_child_and_parent_subdomain(app, client) -> None:
child_subdomain = "api" child_subdomain = "api"
parent_subdomain = "parent" parent_subdomain = "parent"
parent = flask.Blueprint("parent", __name__) parent = flask.Blueprint("parent", __name__)
@ -988,7 +988,9 @@ def test_child_overrides_parent_subdomain(app, client) -> None:
domain_name = "domain.tld" domain_name = "domain.tld"
app.config["SERVER_NAME"] = domain_name app.config["SERVER_NAME"] = domain_name
response = client.get("/", base_url=f"http://{child_subdomain}.{domain_name}") response = client.get(
"/", base_url=f"http://{child_subdomain}.{parent_subdomain}.{domain_name}"
)
assert response.status_code == 200 assert response.status_code == 200