Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

match server names with default scheme and port #1584

Merged
merged 1 commit into from Jun 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions CHANGES.rst
Expand Up @@ -22,8 +22,11 @@ Unreleased
"opera" instead of "chrome". :issue:`1556`
- The platform for Crosswalk on Android is correctly reported as
"android" instead of "chromeos". (:pr:`1572`)
- Issue warning when current server name does not match configured
server name. :issue:`760`
- Issue a warning when the current server name does not match the
configured server name. :issue:`760`
- A configured server name with the default port for a scheme will
match the current server name without the port if the current scheme
matches. :pr:`1584`


Version 0.15.5
Expand Down
31 changes: 23 additions & 8 deletions src/werkzeug/routing.py
Expand Up @@ -1485,41 +1485,56 @@ def bind_to_environ(self, environ, server_name=None, subdomain=None):
:class:`MapAdapter` so that you don't have to pass the path info to
the match method.

.. versionchanged:: 0.5
previously this method accepted a bogus `calculate_subdomain`
parameter that did not have any effect. It was removed because
of that.
.. versionchanged:: 1.0.0
If the passed server name specifies port 443, it will match
if the incoming scheme is ``https`` without a port.

.. versionchanged:: 1.0.0
A warning is shown when the passed server name does not
match the incoming WSGI server name.

.. versionchanged:: 0.8
This will no longer raise a ValueError when an unexpected server
name was passed.

.. versionchanged:: 0.5
previously this method accepted a bogus `calculate_subdomain`
parameter that did not have any effect. It was removed because
of that.

:param environ: a WSGI environment.
:param server_name: an optional server name hint (see above).
:param subdomain: optionally the current subdomain (see above).
"""
environ = _get_environ(environ)

wsgi_server_name = get_host(environ).lower()
scheme = environ["wsgi.url_scheme"]

if server_name is None:
server_name = wsgi_server_name
else:
server_name = server_name.lower()

# strip standard port to match get_host()
if scheme == "http" and server_name.endswith(":80"):
server_name = server_name[:-3]
elif scheme == "https" and server_name.endswith(":443"):
server_name = server_name[:-4]

if subdomain is None and not self.host_matching:
cur_server_name = wsgi_server_name.split(".")
real_server_name = server_name.split(".")
offset = -len(real_server_name)

if cur_server_name[offset:] != real_server_name:
# This can happen even with valid configs if the server was
# accessed directly by IP address under some situations.
# Instead of raising an exception like in Werkzeug 0.7 or
# earlier we go by an invalid subdomain which will result
# in a 404 error on matching.
warnings.warn(
"Current server name '{}' doesn't match configured "
"server name '{}'".format(wsgi_server_name, real_server_name),
"Current server name '{}' doesn't match configured"
" server name '{}'".format(wsgi_server_name, server_name),
stacklevel=2,
)
subdomain = "<invalid>"
Expand All @@ -1539,7 +1554,7 @@ def _get_wsgi_string(name):
server_name,
script_name,
subdomain,
environ["wsgi.url_scheme"],
scheme,
environ["REQUEST_METHOD"],
path_info,
query_args=query_args,
Expand Down
11 changes: 11 additions & 0 deletions tests/test_routing.py
Expand Up @@ -368,6 +368,17 @@ def test_invalid_subdomain_warning():
assert len(record) == 1


@pytest.mark.parametrize(
("base", "name"),
(("http://localhost", "localhost:80"), ("https://localhost", "localhost:443")),
)
def test_server_name_match_default_port(base, name):
environ = create_environ("/foo", base_url=base)
map = r.Map([r.Rule("/foo", endpoint="foo")])
adapter = map.bind_to_environ(environ, server_name=name)
assert adapter.match() == ("foo", {})


def test_adapter_url_parameter_sorting():
map = r.Map(
[r.Rule("/", endpoint="index")], sort_parameters=True, sort_key=lambda x: x[1]
Expand Down