Skip to content

Commit

Permalink
Merge pull request pallets#4935 from pgjones/subdomain
Browse files Browse the repository at this point in the history
Fix subdomain inheritance for nested blueprints
  • Loading branch information
davidism authored Jan 4, 2023
2 parents fa1ee70 + cabda59 commit 836866d
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Version 2.3.0

Unreleased

- Ensure subdomains are applied with nested blueprints. :issue:`4834`


Version 2.2.3
-------------
Expand Down
13 changes: 13 additions & 0 deletions docs/blueprints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ name, and child URLs will be prefixed with the parent's URL prefix.
url_for('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
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.
Expand Down
14 changes: 14 additions & 0 deletions src/flask/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ def register(self, app: "Flask", options: dict) -> None:
:param options: Keyword arguments forwarded from
:meth:`~Flask.register_blueprint`.
.. versionchanged:: 2.3
Nested blueprints now correctly apply subdomains.
.. versionchanged:: 2.0.1
Nested blueprints are registered with their dotted name.
This allows different blueprints with the same name to be
Expand Down Expand Up @@ -453,6 +456,17 @@ def extend(bp_dict, parent_dict):
for blueprint, bp_options in self._blueprints:
bp_options = bp_options.copy()
bp_url_prefix = bp_options.get("url_prefix")
bp_subdomain = bp_options.get("subdomain")

if bp_subdomain is None:
bp_subdomain = blueprint.subdomain

if state.subdomain is not None and bp_subdomain is not None:
bp_options["subdomain"] = bp_subdomain + "." + state.subdomain
elif bp_subdomain is not None:
bp_options["subdomain"] = bp_subdomain
elif state.subdomain is not None:
bp_options["subdomain"] = state.subdomain

if bp_url_prefix is None:
bp_url_prefix = blueprint.url_prefix
Expand Down
49 changes: 49 additions & 0 deletions tests/test_blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,55 @@ def index():
assert response.status_code == 200


def test_nesting_subdomains(app, client) -> None:
subdomain = "api"
parent = flask.Blueprint("parent", __name__)
child = flask.Blueprint("child", __name__)

@child.route("/child/")
def index():
return "child"

parent.register_blueprint(child)
app.register_blueprint(parent, subdomain=subdomain)

client.allow_subdomain_redirects = True

domain_name = "domain.tld"
app.config["SERVER_NAME"] = domain_name
response = client.get("/child/", base_url="http://api." + domain_name)

assert response.status_code == 200


def test_child_and_parent_subdomain(app, client) -> None:
child_subdomain = "api"
parent_subdomain = "parent"
parent = flask.Blueprint("parent", __name__)
child = flask.Blueprint("child", __name__, subdomain=child_subdomain)

@child.route("/")
def index():
return "child"

parent.register_blueprint(child)
app.register_blueprint(parent, subdomain=parent_subdomain)

client.allow_subdomain_redirects = True

domain_name = "domain.tld"
app.config["SERVER_NAME"] = domain_name
response = client.get(
"/", base_url=f"http://{child_subdomain}.{parent_subdomain}.{domain_name}"
)

assert response.status_code == 200

response = client.get("/", base_url=f"http://{parent_subdomain}.{domain_name}")

assert response.status_code == 404


def test_unique_blueprint_names(app, client) -> None:
bp = flask.Blueprint("bp", __name__)
bp2 = flask.Blueprint("bp", __name__)
Expand Down

0 comments on commit 836866d

Please sign in to comment.