Skip to content

Commit fbf11e4

Browse files
committed
Accept any mapping for os.execve env argument
Change env parameter from PyDictRef to ArgMapping so that EnvironmentVarGuard and other mapping types are accepted.
1 parent 4f366d7 commit fbf11e4

File tree

3 files changed

+39
-18
lines changed

3 files changed

+39
-18
lines changed

Lib/test/test_httpservers.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,6 @@ def test_url_collapse_path(self):
994994
msg='path = %r\nGot: %r\nWanted: %r' %
995995
(path, actual, expected))
996996

997-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: Tuples differ: (b"", None, 200) != (b"Hello World\n", "text/html", <HTTPStatus.OK: 200>)')
998997
def test_headers_and_content(self):
999998
res = self.request('/cgi-bin/file1.py')
1000999
self.assertEqual(
@@ -1005,7 +1004,6 @@ def test_issue19435(self):
10051004
res = self.request('///////////nocgi.py/../cgi-bin/nothere.sh')
10061005
self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
10071006

1008-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; b"" != b"1, python, 123456\n"')
10091007
def test_post(self):
10101008
params = urllib.parse.urlencode(
10111009
{'spam' : 1, 'eggs' : 'python', 'bacon' : 123456})
@@ -1014,7 +1012,6 @@ def test_post(self):
10141012

10151013
self.assertEqual(res.read(), b'1, python, 123456' + self.linesep)
10161014

1017-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: b"" != b"32768 32768\n"')
10181015
def test_large_content_length(self):
10191016
for w in range(15, 25):
10201017
size = 1 << w
@@ -1023,7 +1020,8 @@ def test_large_content_length(self):
10231020
res = self.request('/cgi-bin/file7.py', 'POST', body, headers)
10241021
self.assertEqual(res.read(), b'%d %d' % (size, size) + self.linesep)
10251022

1026-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: b"" != b"Hello World\n"')
1023+
# TODO: RUSTPYTHON: times out on macOS CI
1024+
@unittest.expectedFailureIf(sys.platform == 'darwin', 'TODO: RUSTPYTHON; times out on macOS')
10271025
def test_large_content_length_truncated(self):
10281026
with support.swap_attr(self.request_handler, 'timeout', 0.001):
10291027
for w in range(18, 65):
@@ -1037,7 +1035,6 @@ def test_invaliduri(self):
10371035
res.read()
10381036
self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
10391037

1040-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: Tuples differ: (b"Hello World\n", "text/html", <HTTPStatus.OK: 200>) != (b"", None, 200)')
10411038
def test_authorization(self):
10421039
headers = {b'Authorization' : b'Basic ' +
10431040
base64.b64encode(b'username:pass')}
@@ -1046,15 +1043,13 @@ def test_authorization(self):
10461043
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
10471044
(res.read(), res.getheader('Content-type'), res.status))
10481045

1049-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: Tuples differ: (b"Hello World\n", "text/html", <HTTPStatus.OK: 200>) != (b"", None, 200)')
10501046
def test_no_leading_slash(self):
10511047
# http://bugs.python.org/issue2254
10521048
res = self.request('cgi-bin/file1.py')
10531049
self.assertEqual(
10541050
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
10551051
(res.read(), res.getheader('Content-type'), res.status))
10561052

1057-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; ValueError: signal only works in main thread')
10581053
def test_os_environ_is_not_altered(self):
10591054
signature = "Test CGI Server"
10601055
os.environ['SERVER_SOFTWARE'] = signature
@@ -1064,36 +1059,31 @@ def test_os_environ_is_not_altered(self):
10641059
(res.read(), res.getheader('Content-type'), res.status))
10651060
self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
10661061

1067-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; ValueError: signal only works in main thread')
10681062
def test_urlquote_decoding_in_cgi_check(self):
10691063
res = self.request('/cgi-bin%2ffile1.py')
10701064
self.assertEqual(
10711065
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
10721066
(res.read(), res.getheader('Content-type'), res.status))
10731067

1074-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: Tuples differ: (b"Hello World\n", "text/html", <HTTPStatus.OK: 200>) != (b"", None, 200)')
10751068
def test_nested_cgi_path_issue21323(self):
10761069
res = self.request('/cgi-bin/child-dir/file3.py')
10771070
self.assertEqual(
10781071
(b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
10791072
(res.read(), res.getheader('Content-type'), res.status))
10801073

1081-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; ValueError: signal only works in main thread')
10821074
def test_query_with_multiple_question_mark(self):
10831075
res = self.request('/cgi-bin/file4.py?a=b?c=d')
10841076
self.assertEqual(
10851077
(b'a=b?c=d' + self.linesep, 'text/html', HTTPStatus.OK),
10861078
(res.read(), res.getheader('Content-type'), res.status))
10871079

1088-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: Tuples differ: (b"k=aa%2F%2Fbb&//q//p//=//a//b//\n", "text/html", <HTTPStatus.OK: 200>) != (b"", None, 200)')
10891080
def test_query_with_continuous_slashes(self):
10901081
res = self.request('/cgi-bin/file4.py?k=aa%2F%2Fbb&//q//p//=//a//b//')
10911082
self.assertEqual(
10921083
(b'k=aa%2F%2Fbb&//q//p//=//a//b//' + self.linesep,
10931084
'text/html', HTTPStatus.OK),
10941085
(res.read(), res.getheader('Content-type'), res.status))
10951086

1096-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; Tuples differ: (b"", None, 200) != (b"Hello World\n", "text/html", <HTTPStatus.OK: 200>)')
10971087
def test_cgi_path_in_sub_directories(self):
10981088
try:
10991089
CGIHTTPRequestHandler.cgi_directories.append('/sub/dir/cgi-bin')
@@ -1104,7 +1094,6 @@ def test_cgi_path_in_sub_directories(self):
11041094
finally:
11051095
CGIHTTPRequestHandler.cgi_directories.remove('/sub/dir/cgi-bin')
11061096

1107-
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON; AssertionError: b"HTTP_ACCEPT=text/html,text/plain" not found in b""')
11081097
def test_accept(self):
11091098
browser_accept = \
11101099
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'

crates/vm/src/stdlib/nt.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ pub use module::raw_set_handle_inheritable;
66
#[pymodule(name = "nt", with(super::os::_os))]
77
pub(crate) mod module {
88
use crate::{
9-
Py, PyResult, TryFromObject, VirtualMachine,
9+
Py, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
1010
builtins::{PyBaseExceptionRef, PyDictRef, PyListRef, PyStrRef, PyTupleRef},
1111
common::{crt_fd, suppress_iph, windows::ToWideString},
1212
convert::ToPyException,
1313
exceptions::OSErrorBuilder,
14-
function::{Either, OptionalArg},
14+
function::{ArgMapping, Either, OptionalArg},
1515
ospath::{OsPath, OsPathOrFd},
1616
stdlib::os::{_os, DirFd, SupportFunc, TargetIsDirectory},
1717
};
@@ -1212,12 +1212,27 @@ pub(crate) mod module {
12121212
}
12131213
}
12141214

1215+
fn envobj_to_dict(env: ArgMapping, vm: &VirtualMachine) -> PyResult<PyDictRef> {
1216+
let obj = env.obj();
1217+
if let Some(dict) = obj.downcast_ref_if_exact::<crate::builtins::PyDict>(vm) {
1218+
return Ok(dict.to_owned());
1219+
}
1220+
let keys = vm.call_method(obj, "keys", ())?;
1221+
let dict = vm.ctx.new_dict();
1222+
for key in keys.get_iter(vm)?.into_iter::<PyObjectRef>(vm)? {
1223+
let key = key?;
1224+
let val = obj.get_item(&*key, vm)?;
1225+
dict.set_item(&*key, val, vm)?;
1226+
}
1227+
Ok(dict)
1228+
}
1229+
12151230
#[cfg(target_env = "msvc")]
12161231
#[pyfunction]
12171232
fn execve(
12181233
path: OsPath,
12191234
argv: Either<PyListRef, PyTupleRef>,
1220-
env: PyDictRef,
1235+
env: ArgMapping,
12211236
vm: &VirtualMachine,
12221237
) -> PyResult<()> {
12231238
use core::iter::once;
@@ -1246,6 +1261,7 @@ pub(crate) mod module {
12461261
.chain(once(core::ptr::null()))
12471262
.collect();
12481263

1264+
let env = envobj_to_dict(env, vm)?;
12491265
// Build environment strings as "KEY=VALUE\0" wide strings
12501266
let mut env_strings: Vec<widestring::WideCString> = Vec::new();
12511267
for (key, value) in env.into_iter() {

crates/vm/src/stdlib/posix.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub mod module {
3131
builtins::{PyDictRef, PyInt, PyListRef, PyStr, PyTupleRef},
3232
convert::{IntoPyException, ToPyObject, TryFromObject},
3333
exceptions::OSErrorBuilder,
34-
function::{Either, KwArgs, OptionalArg},
34+
function::{ArgMapping, Either, KwArgs, OptionalArg},
3535
ospath::{OsPath, OsPathOrFd},
3636
stdlib::os::{
3737
_os, DirFd, FollowSymlinks, SupportFunc, TargetIsDirectory, fs_metadata,
@@ -1073,11 +1073,26 @@ pub mod module {
10731073
.map_err(|err| err.into_pyexception(vm))
10741074
}
10751075

1076+
fn envobj_to_dict(env: ArgMapping, vm: &VirtualMachine) -> PyResult<PyDictRef> {
1077+
let obj = env.obj();
1078+
if let Some(dict) = obj.downcast_ref_if_exact::<crate::builtins::PyDict>(vm) {
1079+
return Ok(dict.to_owned());
1080+
}
1081+
let keys = vm.call_method(obj, "keys", ())?;
1082+
let dict = vm.ctx.new_dict();
1083+
for key in keys.get_iter(vm)?.into_iter::<PyObjectRef>(vm)? {
1084+
let key = key?;
1085+
let val = obj.get_item(&*key, vm)?;
1086+
dict.set_item(&*key, val, vm)?;
1087+
}
1088+
Ok(dict)
1089+
}
1090+
10761091
#[pyfunction]
10771092
fn execve(
10781093
path: OsPath,
10791094
argv: Either<PyListRef, PyTupleRef>,
1080-
env: PyDictRef,
1095+
env: ArgMapping,
10811096
vm: &VirtualMachine,
10821097
) -> PyResult<()> {
10831098
let path = path.into_cstring(vm)?;
@@ -1095,6 +1110,7 @@ pub mod module {
10951110
return Err(vm.new_value_error("execve() arg 2 first element cannot be empty"));
10961111
}
10971112

1113+
let env = envobj_to_dict(env, vm)?;
10981114
let env = env
10991115
.into_iter()
11001116
.map(|(k, v)| -> PyResult<_> {

0 commit comments

Comments
 (0)