Skip to content

Commit ede0f98

Browse files
authored
Merge pull request #1621 from pallets/template-safe-path
use `posixpath.join` when loading template names
2 parents a292075 + 040088a commit ede0f98

File tree

3 files changed

+15
-6
lines changed

3 files changed

+15
-6
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Unreleased
3636
- The ``groupby`` filter is case-insensitive by default, matching
3737
other comparison filters. Added the ``case_sensitive`` parameter to
3838
control this. :issue:`1463`
39+
- Windows drive-relative path segments in template names will not
40+
result in ``FileSystemLoader`` and ``PackageLoader`` loading from
41+
drive-relative paths. :pr:`1621`
3942

4043

4144
Version 3.0.3

src/jinja2/loaders.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
import importlib.util
55
import os
6+
import posixpath
67
import sys
78
import typing as t
89
import weakref
@@ -193,7 +194,9 @@ def get_source(
193194
) -> t.Tuple[str, str, t.Callable[[], bool]]:
194195
pieces = split_template_path(template)
195196
for searchpath in self.searchpath:
196-
filename = os.path.join(searchpath, *pieces)
197+
# Use posixpath even on Windows to avoid "drive:" or UNC
198+
# segments breaking out of the search directory.
199+
filename = posixpath.join(searchpath, *pieces)
197200
f = open_if_exists(filename)
198201
if f is None:
199202
continue
@@ -296,7 +299,7 @@ def __init__(
296299
if isinstance(loader, zipimport.zipimporter):
297300
self._archive = loader.archive
298301
pkgdir = next(iter(spec.submodule_search_locations)) # type: ignore
299-
template_root = os.path.join(pkgdir, package_path)
302+
template_root = os.path.join(pkgdir, package_path).rstrip(os.path.sep)
300303
else:
301304
roots: t.List[str] = []
302305

@@ -326,7 +329,9 @@ def __init__(
326329
def get_source(
327330
self, environment: "Environment", template: str
328331
) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]:
329-
p = os.path.join(self._template_root, *split_template_path(template))
332+
# Use posixpath even on Windows to avoid "drive:" or UNC
333+
# segments breaking out of the search directory.
334+
p = posixpath.join(self._template_root, *split_template_path(template))
330335
up_to_date: t.Optional[t.Callable[[], bool]]
331336

332337
if self._archive is None:

tests/test_loader.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import importlib.util
44
import os
55
import platform
6+
import posixpath
67
import shutil
78
import sys
89
import tempfile
@@ -303,7 +304,7 @@ def package_dir_loader(monkeypatch):
303304
def test_package_dir_source(package_dir_loader, template, expect):
304305
source, name, up_to_date = package_dir_loader.get_source(None, template)
305306
assert source.rstrip() == expect
306-
assert name.endswith(os.path.join(*split_template_path(template)))
307+
assert name.endswith(posixpath.join(*split_template_path(template)))
307308
assert up_to_date()
308309

309310

@@ -325,7 +326,7 @@ def package_file_loader(monkeypatch):
325326
def test_package_file_source(package_file_loader, template, expect):
326327
source, name, up_to_date = package_file_loader.get_source(None, template)
327328
assert source.rstrip() == expect
328-
assert name.endswith(os.path.join(*split_template_path(template)))
329+
assert name.endswith(posixpath.join(*split_template_path(template)))
329330
assert up_to_date()
330331

331332

@@ -348,7 +349,7 @@ def package_zip_loader(monkeypatch):
348349
def test_package_zip_source(package_zip_loader, template, expect):
349350
source, name, up_to_date = package_zip_loader.get_source(None, template)
350351
assert source.rstrip() == expect
351-
assert name.endswith(os.path.join(*split_template_path(template)))
352+
assert name.endswith(posixpath.join(*split_template_path(template)))
352353
assert up_to_date is None
353354

354355

0 commit comments

Comments
 (0)