@@ -53,3 +53,107 @@ def test_Loader_initialisation_with_neither_TMP_HOME_set(tmp_dir_fixture):
5353
5454 loader = Loader (ctx = {})
5555 assert isinstance (loader .session , Session )
56+
57+ def test_DefaultFetcher_urljoin_win32 (tmp_dir_fixture ):
58+ import os
59+ import sys
60+ from schema_salad .ref_resolver import DefaultFetcher
61+ from requests import Session
62+
63+ # Ensure HOME is set.
64+ os .environ ["HOME" ] = tmp_dir_fixture
65+
66+ actual_platform = sys .platform
67+ try :
68+ # For this test always pretend we're on Windows
69+ sys .platform = "win32"
70+ fetcher = DefaultFetcher ({}, None )
71+ # Relative path, same folder
72+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "soup.cwl" )
73+ assert url == "file:///C:/Users/fred/soup.cwl"
74+ # Relative path, sub folder
75+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "foo/soup.cwl" )
76+ assert url == "file:///C:/Users/fred/foo/soup.cwl"
77+ # relative climb-up path
78+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "../alice/soup.cwl" )
79+ assert url == "file:///C:/Users/alice/soup.cwl"
80+
81+ # Path with drive: should not be treated as relative to directory
82+ # Note: \ would already have been converted to / by resolve_ref()
83+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "c:/bar/soup.cwl" )
84+ assert url == "file:///c:/bar/soup.cwl"
85+ # /C:/ (regular URI absolute path)
86+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "/c:/bar/soup.cwl" )
87+ assert url == "file:///c:/bar/soup.cwl"
88+ # Relative, change drive
89+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "D:/baz/soup.cwl" )
90+ assert url == "file:///d:/baz/soup.cwl"
91+ # Relative from root of base's D: drive
92+ url = fetcher .urljoin ("file:///d:/baz/soup.cwl" , "/foo/soup.cwl" )
93+ assert url == "file:///d:/foo/soup.cwl"
94+
95+ # resolving absolute non-drive URIs still works
96+ url = fetcher .urljoin ("file:///C:/Users/fred/foo.cwl" , "http://example.com/bar/soup.cwl" )
97+ assert url == "http://example.com/bar/soup.cwl"
98+ # and of course relative paths from http://
99+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "soup.cwl" )
100+ assert url == "http://example.com/fred/soup.cwl"
101+
102+ # Stay on http:// and same host
103+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "/bar/soup.cwl" )
104+ assert url == "http://example.com/bar/soup.cwl"
105+
106+
107+ # Security concern - can't resolve file: from http:
108+ with pytest .raises (ValueError ):
109+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "file:///c:/bar/soup.cwl" )
110+ # Drive-relative -- should NOT return "absolute" URI c:/bar/soup.cwl"
111+ # as that is a potential remote exploit
112+ with pytest .raises (ValueError ):
113+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "c:/bar/soup.cwl" )
114+
115+ finally :
116+ sys .platform = actual_platform
117+
118+ def test_DefaultFetcher_urljoin_linux (tmp_dir_fixture ):
119+ import os
120+ import sys
121+ from schema_salad .ref_resolver import DefaultFetcher
122+ from requests import Session
123+
124+ # Ensure HOME is set.
125+ os .environ ["HOME" ] = tmp_dir_fixture
126+
127+ actual_platform = sys .platform
128+ try :
129+ # Pretend it's Linux (e.g. not win32)
130+ sys .platform = "linux2"
131+ fetcher = DefaultFetcher ({}, None )
132+ url = fetcher .urljoin ("file:///home/fred/foo.cwl" , "soup.cwl" )
133+ assert url == "file:///home/fred/soup.cwl"
134+
135+ url = fetcher .urljoin ("file:///home/fred/foo.cwl" , "../alice/soup.cwl" )
136+ assert url == "file:///home/alice/soup.cwl"
137+ # relative from root
138+ url = fetcher .urljoin ("file:///home/fred/foo.cwl" , "/baz/soup.cwl" )
139+ assert url == "file:///baz/soup.cwl"
140+
141+ url = fetcher .urljoin ("file:///home/fred/foo.cwl" , "http://example.com/bar/soup.cwl" )
142+ assert url == "http://example.com/bar/soup.cwl"
143+
144+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "soup.cwl" )
145+ assert url == "http://example.com/fred/soup.cwl"
146+
147+ # Root-relative -- here relative to http host, not file:///
148+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "/bar/soup.cwl" )
149+ assert url == "http://example.com/bar/soup.cwl"
150+
151+ # Security concern - can't resolve file: from http:
152+ with pytest .raises (ValueError ):
153+ url = fetcher .urljoin ("http://example.com/fred/foo.cwl" , "file:///bar/soup.cwl" )
154+
155+ # But this one is not "dangerous" on Linux
156+ fetcher .urljoin ("http://example.com/fred/foo.cwl" , "c:/bar/soup.cwl" )
157+
158+ finally :
159+ sys .platform = actual_platform
0 commit comments