From d99f72d12698d86e7ebcb894f3c6c729e2b6c067 Mon Sep 17 00:00:00 2001 From: David Lord Date: Thu, 7 Nov 2024 08:01:56 -0800 Subject: [PATCH] wrap IPv6 SERVER_NAME in [] --- CHANGES.rst | 3 +++ src/werkzeug/sansio/utils.py | 8 ++++++++ tests/sansio/test_utils.py | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 6a2fd2ed4..27a89e83e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -9,6 +9,9 @@ Unreleased ``list``, ``tuple``, or ``set`` when passing multiple values. It had been changed to accept any ``Collection``, but this matched types that should be treated as single values, such as ``bytes``. :issue:`2994` +- When the ``Host`` header is not set and ``Request.host`` falls back to the + WSGI ``SERVER_NAME`` value, if that value is an IPv6 address it is wrapped + in ``[]`` to match the ``Host`` header. :issue:`2993` Version 3.1.2 diff --git a/src/werkzeug/sansio/utils.py b/src/werkzeug/sansio/utils.py index 14fa0ac88..ff7ceda34 100644 --- a/src/werkzeug/sansio/utils.py +++ b/src/werkzeug/sansio/utils.py @@ -71,6 +71,9 @@ def get_host( :return: Host, with port if necessary. :raise ~werkzeug.exceptions.SecurityError: If the host is not trusted. + + .. versionchanged:: 3.1.3 + If ``SERVER_NAME`` is IPv6, it is wrapped in ``[]``. """ host = "" @@ -79,6 +82,11 @@ def get_host( elif server is not None: host = server[0] + # If SERVER_NAME is IPv6, wrap it in [] to match Host header. + # Check for : because domain or IPv4 can't have that. + if ":" in host and host[0] != "[": + host = f"[{host}]" + if server[1] is not None: host = f"{host}:{server[1]}" diff --git a/tests/sansio/test_utils.py b/tests/sansio/test_utils.py index d43de66c2..a63e7c660 100644 --- a/tests/sansio/test_utils.py +++ b/tests/sansio/test_utils.py @@ -14,12 +14,16 @@ ("https", "spam", None, "spam"), ("https", "spam:443", None, "spam"), ("http", "spam:8080", None, "spam:8080"), + ("http", "127.0.0.1:8080", None, "127.0.0.1:8080"), + ("http", "[::1]:8080", None, "[::1]:8080"), ("ws", "spam", None, "spam"), ("ws", "spam:80", None, "spam"), ("wss", "spam", None, "spam"), ("wss", "spam:443", None, "spam"), ("http", None, ("spam", 80), "spam"), ("http", None, ("spam", 8080), "spam:8080"), + ("http", None, ("127.0.0.1", 8080), "127.0.0.1:8080"), + ("http", None, ("::1", 8080), "[::1]:8080"), ("http", None, ("unix/socket", None), "unix/socket"), ("http", "spam", ("eggs", 80), "spam"), ],