From f76cd324ec52f23000641aac5e0544b9bc2f0a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:09:46 +0100 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9C=A8=20Add=20util=20to=20get=20route?= =?UTF-8?q?=20path=20from=20scope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/_utils.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/starlette/_utils.py b/starlette/_utils.py index 26854f3d4..60213fef0 100644 --- a/starlette/_utils.py +++ b/starlette/_utils.py @@ -1,9 +1,12 @@ import asyncio import functools +import re import sys import typing from contextlib import contextmanager +from starlette.types import Scope + if sys.version_info >= (3, 10): # pragma: no cover from typing import TypeGuard else: # pragma: no cover @@ -86,3 +89,8 @@ def collapse_excgroups() -> typing.Generator[None, None, None]: exc = exc.exceptions[0] # pragma: no cover raise exc + +def get_route_path(scope: Scope) -> str: + root_path = scope.get("root_path", "") + route_path = re.sub(r"^" + root_path, "", scope["path"]) + return route_path From dd5c99fa6550fa081eaafdbd0a430d43f3b88c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:16:35 +0100 Subject: [PATCH 02/12] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20extractin?= =?UTF-8?q?g=20the=20local=20route=5Fpath=20from=20the=20scope,=20and=20cr?= =?UTF-8?q?eating=20the=20child=20scope=20with=20its=20own=20root=5Fpat,?= =?UTF-8?q?=20this=20allows=20sub-apps=20(e.g.=20WSGIMiddleware)=20to=20kn?= =?UTF-8?q?ow=20where=20it=20was=20mounted,=20and=20from=20which=20path=20?= =?UTF-8?q?prefix=20starts=20the=20path=20its=20sub-app=20should=20handle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/routing.py | 42 ++++++++++++++++++++++------------------ starlette/staticfiles.py | 6 +++--- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/starlette/routing.py b/starlette/routing.py index c8c854d2c..b5b032237 100644 --- a/starlette/routing.py +++ b/starlette/routing.py @@ -10,7 +10,7 @@ from enum import Enum from starlette._exception_handler import wrap_app_handling_exceptions -from starlette._utils import is_async_callable +from starlette._utils import get_route_path, is_async_callable from starlette.concurrency import run_in_threadpool from starlette.convertors import CONVERTOR_TYPES, Convertor from starlette.datastructures import URL, Headers, URLPath @@ -253,9 +253,8 @@ def __init__( def matches(self, scope: Scope) -> typing.Tuple[Match, Scope]: path_params: "typing.Dict[str, typing.Any]" if scope["type"] == "http": - root_path = scope.get("route_root_path", scope.get("root_path", "")) - path = scope.get("route_path", re.sub(r"^" + root_path, "", scope["path"])) - match = self.path_regex.match(path) + route_path = get_route_path(scope) + match = self.path_regex.match(route_path) if match: matched_params = match.groupdict() for key, value in matched_params.items(): @@ -343,9 +342,8 @@ def __init__( def matches(self, scope: Scope) -> typing.Tuple[Match, Scope]: path_params: "typing.Dict[str, typing.Any]" if scope["type"] == "websocket": - root_path = scope.get("route_root_path", scope.get("root_path", "")) - path = scope.get("route_path", re.sub(r"^" + root_path, "", scope["path"])) - match = self.path_regex.match(path) + route_path = get_route_path(scope) + match = self.path_regex.match(route_path) if match: matched_params = match.groupdict() for key, value in matched_params.items(): @@ -418,9 +416,8 @@ def routes(self) -> typing.List[BaseRoute]: def matches(self, scope: Scope) -> typing.Tuple[Match, Scope]: path_params: "typing.Dict[str, typing.Any]" if scope["type"] in ("http", "websocket"): - path = scope["path"] - root_path = scope.get("route_root_path", scope.get("root_path", "")) - route_path = scope.get("route_path", re.sub(r"^" + root_path, "", path)) + root_path = scope.get("root_path", "") + route_path = get_route_path(scope) match = self.path_regex.match(route_path) if match: matched_params = match.groupdict() @@ -430,11 +427,21 @@ def matches(self, scope: Scope) -> typing.Tuple[Match, Scope]: matched_path = route_path[: -len(remaining_path)] path_params = dict(scope.get("path_params", {})) path_params.update(matched_params) - root_path = scope.get("root_path", "") child_scope = { "path_params": path_params, - "route_root_path": root_path + matched_path, - "route_path": remaining_path, + # app_root_path will only be set at the top level scope, + # initialized with the (optional) value of a root_path + # set above/before Starlette. And even though any + # mount will have its own child scope with its own respective + # root_path, the app_root_path will always be available in all + # the child scopes with the same top level value because it's + # set only once here with a default, any other child scope will + # just inherit that app_root_path default value stored in the + # scope. All this is needed to support Request.url_for(), as it + # uses the app_root_path to build the URL path. + "app_root_path": scope.get("app_root_path", root_path), + "root_path": root_path + matched_path, + # "path": remaining_path, "endpoint": self.app, } return Match.FULL, child_scope @@ -785,15 +792,12 @@ async def app(self, scope: Scope, receive: Receive, send: Send) -> None: await partial.handle(scope, receive, send) return - root_path = scope.get("route_root_path", scope.get("root_path", "")) - path = scope.get("route_path", re.sub(r"^" + root_path, "", scope["path"])) - if scope["type"] == "http" and self.redirect_slashes and path != "/": + route_path = get_route_path(scope) + if scope["type"] == "http" and self.redirect_slashes and route_path != "/": redirect_scope = dict(scope) - if path.endswith("/"): - redirect_scope["route_path"] = path.rstrip("/") + if route_path.endswith("/"): redirect_scope["path"] = redirect_scope["path"].rstrip("/") else: - redirect_scope["route_path"] = path + "/" redirect_scope["path"] = redirect_scope["path"] + "/" for route in self.routes: diff --git a/starlette/staticfiles.py b/starlette/staticfiles.py index 895105a7d..9f476d7ba 100644 --- a/starlette/staticfiles.py +++ b/starlette/staticfiles.py @@ -8,6 +8,7 @@ import anyio import anyio.to_thread +from starlette._utils import get_route_path from starlette.datastructures import URL, Headers from starlette.exceptions import HTTPException from starlette.responses import FileResponse, RedirectResponse, Response @@ -110,9 +111,8 @@ def get_path(self, scope: Scope) -> str: Given the ASGI scope, return the `path` string to serve up, with OS specific path separators, and any '..', '.' components removed. """ - root_path = scope.get("route_root_path", scope.get("root_path", "")) - path = scope.get("route_path", re.sub(r"^" + root_path, "", scope["path"])) - return os.path.normpath(os.path.join(*path.split("/"))) # type: ignore[no-any-return] # noqa: E501 + route_path = get_route_path(scope) + return os.path.normpath(os.path.join(*route_path.split("/"))) # type: ignore[no-any-return] # noqa: E501 async def get_response(self, path: str, scope: Scope) -> Response: """ From 65fb7a9f6b37b07011d71df22fb7309228a7d20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:17:59 +0100 Subject: [PATCH 03/12] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20datastruc?= =?UTF-8?q?tures=20and=20request=20to=20be=20conformant=20with=20the=20ASG?= =?UTF-8?q?I=20spec,=20respecting=20root=5Fpath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/datastructures.py | 2 +- starlette/requests.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/starlette/datastructures.py b/starlette/datastructures.py index a0c3ba140..e12957f50 100644 --- a/starlette/datastructures.py +++ b/starlette/datastructures.py @@ -30,7 +30,7 @@ def __init__( assert not components, 'Cannot set both "scope" and "**components".' scheme = scope.get("scheme", "http") server = scope.get("server", None) - path = scope.get("root_path", "") + scope["path"] + path = scope["path"] query_string = scope.get("query_string", b"") host_header = None diff --git a/starlette/requests.py b/starlette/requests.py index 83a52aca1..e51223bab 100644 --- a/starlette/requests.py +++ b/starlette/requests.py @@ -99,9 +99,18 @@ def url(self) -> URL: def base_url(self) -> URL: if not hasattr(self, "_base_url"): base_url_scope = dict(self.scope) - base_url_scope["path"] = "/" + # This is used by request.url_for, it might be used inside a Mount which + # would have its own child scope with its own root_path, but the base URL + # for url_for should still be the top level app root path. + app_root_path = base_url_scope.get( + "app_root_path", base_url_scope.get("root_path", "") + ) + path = app_root_path + if not path.endswith("/"): + path += "/" + base_url_scope["path"] = path base_url_scope["query_string"] = b"" - base_url_scope["root_path"] = base_url_scope.get("root_path", "") + base_url_scope["root_path"] = app_root_path self._base_url = URL(scope=base_url_scope) return self._base_url From e7f064602e80ee308cd886eeff68a90ddbc37c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:19:03 +0100 Subject: [PATCH 04/12] =?UTF-8?q?=E2=9C=85=20Add=20and=20update=20tests=20?= =?UTF-8?q?for=20root=5Fpath=20with=20mounted=20apps=20that=20don't=20know?= =?UTF-8?q?=20about=20Starlette=20internals=20(e.g.=20the=20route=5Froot?= =?UTF-8?q?=5Fpath=20extension=20scope=20key=20that=20was=20added=20in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_routing.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/tests/test_routing.py b/tests/test_routing.py index 5c12ebabe..a530a917f 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -1,5 +1,6 @@ import contextlib import functools +import json import typing import uuid @@ -1242,6 +1243,19 @@ async def echo_paths(request: Request, name: str): ) +async def pure_asgi_echo_paths(scope: Scope, receive: Receive, send: Send, name: str): + data = {"name": name, "path": scope["path"], "root_path": scope["root_path"]} + content = json.dumps(data).encode("utf-8") + await send( + { + "type": "http.response.start", + "status": 200, + "headers": [(b"content-type", b"application/json")], + } + ) + await send({"type": "http.response.body", "body": content}) + + echo_paths_routes = [ Route( "/path", @@ -1250,7 +1264,11 @@ async def echo_paths(request: Request, name: str): methods=["GET"], ), Mount( - "/root", + "/asgipath", + app=functools.partial(pure_asgi_echo_paths, name="asgipath") + ), + Mount( + "/sub", name="mount", routes=[ Route( @@ -1258,7 +1276,7 @@ async def echo_paths(request: Request, name: str): functools.partial(echo_paths, name="subpath"), name="subpath", methods=["GET"], - ) + ), ], ), ] @@ -1276,11 +1294,22 @@ def test_paths_with_root_path(test_client_factory: typing.Callable[..., TestClie "path": "/root/path", "root_path": "/root", } + response = client.get("/root/asgipath/") + assert response.status_code == 200 + assert response.json() == { + "name": "asgipath", + "path": "/root/asgipath/", + # Things that mount other ASGI apps, like WSGIMiddleware, would not be aware + # of the prefixed path, and would have their own notion of their own paths, + # so they need to be able to rely on the root_path to know the location they + # are mounted on + "root_path": "/root/asgipath", + } - response = client.get("/root/root/path") + response = client.get("/root/sub/path") assert response.status_code == 200 assert response.json() == { "name": "subpath", - "path": "/root/root/path", - "root_path": "/root", + "path": "/root/sub/path", + "root_path": "/root/sub", } From 5a696d8e46f40ed92c8c9adf9f8b4e5433791b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:20:45 +0100 Subject: [PATCH 05/12] =?UTF-8?q?=E2=9C=85=20Update=20test=20for=20root=5F?= =?UTF-8?q?path,=20TestClient=20was=20not=20requiring=20paths=20under=20a?= =?UTF-8?q?=20root=5Fpath=20to=20pass=20the=20root=5Fpath,=20which=20is=20?= =?UTF-8?q?what=20clients=20would=20have=20to=20do=20if=20the=20app=20is?= =?UTF-8?q?=20mounted.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_routing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_routing.py b/tests/test_routing.py index a530a917f..923346df1 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -564,12 +564,12 @@ def test_url_for_with_root_path(test_client_factory): client = test_client_factory( app, base_url="https://www.example.org/", root_path="/sub_path" ) - response = client.get("/") + response = client.get("/sub_path/") assert response.json() == { "index": "https://www.example.org/sub_path/", "submount": "https://www.example.org/sub_path/submount/", } - response = client.get("/submount/") + response = client.get("/sub_path/submount/") assert response.json() == { "index": "https://www.example.org/sub_path/", "submount": "https://www.example.org/sub_path/submount/", From 3a438de0c8f98b5503f75f86212f3e4c0262bbc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:57:05 +0100 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=8E=A8=20Fix=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/_utils.py | 1 + starlette/staticfiles.py | 1 - tests/test_routing.py | 5 +---- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/starlette/_utils.py b/starlette/_utils.py index 60213fef0..15ccd92a4 100644 --- a/starlette/_utils.py +++ b/starlette/_utils.py @@ -90,6 +90,7 @@ def collapse_excgroups() -> typing.Generator[None, None, None]: raise exc + def get_route_path(scope: Scope) -> str: root_path = scope.get("root_path", "") route_path = re.sub(r"^" + root_path, "", scope["path"]) diff --git a/starlette/staticfiles.py b/starlette/staticfiles.py index 9f476d7ba..dabe6569f 100644 --- a/starlette/staticfiles.py +++ b/starlette/staticfiles.py @@ -1,6 +1,5 @@ import importlib.util import os -import re import stat import typing from email.utils import parsedate diff --git a/tests/test_routing.py b/tests/test_routing.py index 923346df1..b1f864cf2 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -1263,10 +1263,7 @@ async def pure_asgi_echo_paths(scope: Scope, receive: Receive, send: Send, name: name="path", methods=["GET"], ), - Mount( - "/asgipath", - app=functools.partial(pure_asgi_echo_paths, name="asgipath") - ), + Mount("/asgipath", app=functools.partial(pure_asgi_echo_paths, name="asgipath")), Mount( "/sub", name="mount", From 733619169ccc7535b8e67db4b288bf531a2421ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 21:59:17 +0100 Subject: [PATCH 07/12] =?UTF-8?q?=F0=9F=8E=A8=20Remove=20type=20ignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/staticfiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starlette/staticfiles.py b/starlette/staticfiles.py index dabe6569f..0101b11bc 100644 --- a/starlette/staticfiles.py +++ b/starlette/staticfiles.py @@ -111,7 +111,7 @@ def get_path(self, scope: Scope) -> str: with OS specific path separators, and any '..', '.' components removed. """ route_path = get_route_path(scope) - return os.path.normpath(os.path.join(*route_path.split("/"))) # type: ignore[no-any-return] # noqa: E501 + return os.path.normpath(os.path.join(*route_path.split("/"))) # noqa: E501 async def get_response(self, path: str, scope: Scope) -> Response: """ From 2c0ca9711840c04f8c2e1ebfa57191e6270ff56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 7 Jan 2024 22:04:31 +0100 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=94=A5=20Remove=20unnecessary=20com?= =?UTF-8?q?ment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/routing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/starlette/routing.py b/starlette/routing.py index b5b032237..ee31750f1 100644 --- a/starlette/routing.py +++ b/starlette/routing.py @@ -441,7 +441,6 @@ def matches(self, scope: Scope) -> typing.Tuple[Match, Scope]: # uses the app_root_path to build the URL path. "app_root_path": scope.get("app_root_path", root_path), "root_path": root_path + matched_path, - # "path": remaining_path, "endpoint": self.app, } return Match.FULL, child_scope From 0d6753fd609e74486b5a0209863d76bc5b5369b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 8 Jan 2024 16:54:48 +0100 Subject: [PATCH 09/12] =?UTF-8?q?=E2=9C=A8=20Update=20(deprecated)=20WSGIM?= =?UTF-8?q?iddleware=20to=20be=20compatible=20with=20the=20updated=20root?= =?UTF-8?q?=5Fpath,=20taking=20pieces=20from=20a2wsgi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/middleware/wsgi.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/starlette/middleware/wsgi.py b/starlette/middleware/wsgi.py index 95578c9d2..11482cf20 100644 --- a/starlette/middleware/wsgi.py +++ b/starlette/middleware/wsgi.py @@ -1,5 +1,6 @@ import io import math +import os import sys import typing import warnings @@ -15,15 +16,32 @@ DeprecationWarning, ) +ENC, ESC = sys.getfilesystemencoding(), "surrogateescape" + + +def unicode_to_wsgi(u): + """Convert an environment variable to a WSGI "bytes-as-unicode" string""" + return u.encode(ENC, ESC).decode("iso-8859-1") + def build_environ(scope: Scope, body: bytes) -> typing.Dict[str, typing.Any]: """ Builds a scope and request body into a WSGI environ object. """ + + script_name = scope.get("root_path", "").encode("utf8").decode("latin1") + path_info = scope["path"].encode("utf8").decode("latin1") + if path_info.startswith(script_name): + path_info = path_info[len(script_name) :] + + script_name_environ_var = os.environ.get("SCRIPT_NAME", "") + if script_name_environ_var: + script_name = unicode_to_wsgi(script_name_environ_var) + environ = { "REQUEST_METHOD": scope["method"], - "SCRIPT_NAME": scope.get("root_path", "").encode("utf8").decode("latin1"), - "PATH_INFO": scope["path"].encode("utf8").decode("latin1"), + "SCRIPT_NAME": script_name, + "PATH_INFO": path_info, "QUERY_STRING": scope["query_string"].decode("ascii"), "SERVER_PROTOCOL": f"HTTP/{scope['http_version']}", "wsgi.version": (1, 0), From 0d37c874f2547597de4d28b2c21eb38a7f6fa470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 8 Jan 2024 16:57:16 +0100 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=8E=A8=20Fix=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/middleware/wsgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starlette/middleware/wsgi.py b/starlette/middleware/wsgi.py index 11482cf20..fa72dd945 100644 --- a/starlette/middleware/wsgi.py +++ b/starlette/middleware/wsgi.py @@ -19,7 +19,7 @@ ENC, ESC = sys.getfilesystemencoding(), "surrogateescape" -def unicode_to_wsgi(u): +def unicode_to_wsgi(u: str) -> str: """Convert an environment variable to a WSGI "bytes-as-unicode" string""" return u.encode(ENC, ESC).decode("iso-8859-1") From a010c3382f001946abd5d00a000c15c9a77f859f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 8 Jan 2024 17:24:36 +0100 Subject: [PATCH 11/12] =?UTF-8?q?=E2=9C=85=20Update=20test=20for=20WSGIMid?= =?UTF-8?q?dleware=20with=20root=5Fpath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/middleware/test_wsgi.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/middleware/test_wsgi.py b/tests/middleware/test_wsgi.py index fe527e373..316cb191f 100644 --- a/tests/middleware/test_wsgi.py +++ b/tests/middleware/test_wsgi.py @@ -92,7 +92,8 @@ def test_build_environ(): "http_version": "1.1", "method": "GET", "scheme": "https", - "path": "/", + "path": "/sub/", + "root_path": "/sub", "query_string": b"a=123&b=456", "headers": [ (b"host", b"www.example.org"), @@ -117,7 +118,7 @@ def test_build_environ(): "QUERY_STRING": "a=123&b=456", "REMOTE_ADDR": "134.56.78.4", "REQUEST_METHOD": "GET", - "SCRIPT_NAME": "", + "SCRIPT_NAME": "/sub", "SERVER_NAME": "www.example.org", "SERVER_PORT": 443, "SERVER_PROTOCOL": "HTTP/1.1", From 7be8c7a1a3c2383486e3b25e3196b5ae9ff1c278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Mon, 8 Jan 2024 17:32:50 +0100 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=94=A5=20Remove=20logic/features=20?= =?UTF-8?q?not=20in=20the=20original=20(deprecated)=20WSGIMiddleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- starlette/middleware/wsgi.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/starlette/middleware/wsgi.py b/starlette/middleware/wsgi.py index fa72dd945..2ce83b074 100644 --- a/starlette/middleware/wsgi.py +++ b/starlette/middleware/wsgi.py @@ -1,6 +1,5 @@ import io import math -import os import sys import typing import warnings @@ -16,13 +15,6 @@ DeprecationWarning, ) -ENC, ESC = sys.getfilesystemencoding(), "surrogateescape" - - -def unicode_to_wsgi(u: str) -> str: - """Convert an environment variable to a WSGI "bytes-as-unicode" string""" - return u.encode(ENC, ESC).decode("iso-8859-1") - def build_environ(scope: Scope, body: bytes) -> typing.Dict[str, typing.Any]: """ @@ -34,10 +26,6 @@ def build_environ(scope: Scope, body: bytes) -> typing.Dict[str, typing.Any]: if path_info.startswith(script_name): path_info = path_info[len(script_name) :] - script_name_environ_var = os.environ.get("SCRIPT_NAME", "") - if script_name_environ_var: - script_name = unicode_to_wsgi(script_name_environ_var) - environ = { "REQUEST_METHOD": scope["method"], "SCRIPT_NAME": script_name,