From 31d7ba8f8c8ef595fd587b4a4594e435abac66f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=2E=20K=C3=A4rkk=C3=A4inen?= <98187+Tronic@users.noreply.github.com> Date: Thu, 13 Jul 2023 21:01:02 +0100 Subject: [PATCH] Add request.client_ip (#2790) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: L. Kärkkäinen --- sanic/request/types.py | 24 ++++++++++++++++++------ tests/test_requests.py | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/sanic/request/types.py b/sanic/request/types.py index 98f6e908..53d1a402 100644 --- a/sanic/request/types.py +++ b/sanic/request/types.py @@ -838,19 +838,31 @@ class Request(Generic[sanic_type, ctx_type]): @property def remote_addr(self) -> str: """ - Client IP address, if available. - 1. proxied remote address `self.forwarded['for']` - 2. local remote address `self.ip` + Client IP address, if available from proxy. :return: IPv4, bracketed IPv6, UNIX socket name or arbitrary string :rtype: str """ if not hasattr(self, "_remote_addr"): - self._remote_addr = str( - self.forwarded.get("for", "") - ) # or self.ip + self._remote_addr = str(self.forwarded.get("for", "")) return self._remote_addr + @property + def client_ip(self) -> str: + """ + Client IP address. + 1. proxied remote address `self.forwarded['for']` + 2. local peer address `self.ip` + + New in Sanic 23.6. Prefer this over `remote_addr` for determining the + client address regardless of whether the service runs behind a proxy + or not (proxy deployment needs separate configuration). + + :return: IPv4, bracketed IPv6, UNIX socket name or arbitrary string + :rtype: str + """ + return self.remote_addr or self.ip + @property def scheme(self) -> str: """ diff --git a/tests/test_requests.py b/tests/test_requests.py index 4a995d4c..6719025b 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -513,6 +513,7 @@ def test_standard_forwarded(app): request, response = app.test_client.get("/", headers=headers) assert response.json == {"for": "127.0.0.2", "proto": "ws"} assert request.remote_addr == "127.0.0.2" + assert request.client_ip == "127.0.0.2" assert request.scheme == "ws" assert request.server_name == "local.site" assert request.server_port == 80 @@ -737,6 +738,7 @@ def test_remote_addr_with_two_proxies(app): headers = {"X-Forwarded-For": "127.0.1.1"} request, response = app.test_client.get("/", headers=headers) assert request.remote_addr == "" + assert request.client_ip == "127.0.0.1" assert response.body == b"" headers = {"X-Forwarded-For": "127.0.0.1, 127.0.1.2"}