asyncio, Tulip issue 130: Add more checks on subprocess_exec/subprocess_shell

parameters
This commit is contained in:
Victor Stinner 2014-02-11 11:44:56 +01:00
parent a125497ea3
commit 4e8d2f25e2
3 changed files with 64 additions and 7 deletions

View File

@ -558,7 +558,7 @@ class BaseEventLoop(events.AbstractEventLoop):
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=False, shell=True, bufsize=0, universal_newlines=False, shell=True, bufsize=0,
**kwargs): **kwargs):
if not isinstance(cmd, str): if not isinstance(cmd, (bytes, str)):
raise ValueError("cmd must be a string") raise ValueError("cmd must be a string")
if universal_newlines: if universal_newlines:
raise ValueError("universal_newlines must be False") raise ValueError("universal_newlines must be False")
@ -572,7 +572,7 @@ class BaseEventLoop(events.AbstractEventLoop):
return transport, protocol return transport, protocol
@tasks.coroutine @tasks.coroutine
def subprocess_exec(self, protocol_factory, *args, stdin=subprocess.PIPE, def subprocess_exec(self, protocol_factory, program, *args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=False, shell=False, bufsize=0, universal_newlines=False, shell=False, bufsize=0,
**kwargs): **kwargs):
@ -582,9 +582,15 @@ class BaseEventLoop(events.AbstractEventLoop):
raise ValueError("shell must be False") raise ValueError("shell must be False")
if bufsize != 0: if bufsize != 0:
raise ValueError("bufsize must be 0") raise ValueError("bufsize must be 0")
popen_args = (program,) + args
for arg in popen_args:
if not isinstance(arg, (str, bytes)):
raise TypeError("program arguments must be "
"a bytes or text string, not %s"
% type(arg).__name__)
protocol = protocol_factory() protocol = protocol_factory()
transport = yield from self._make_subprocess_transport( transport = yield from self._make_subprocess_transport(
protocol, args, False, stdin, stdout, stderr, bufsize, **kwargs) protocol, popen_args, False, stdin, stdout, stderr, bufsize, **kwargs)
return transport, protocol return transport, protocol
def _add_callback(self, handle): def _add_callback(self, handle):

View File

@ -180,7 +180,7 @@ def create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None,
return Process(transport, protocol, loop) return Process(transport, protocol, loop)
@tasks.coroutine @tasks.coroutine
def create_subprocess_exec(*args, stdin=None, stdout=None, stderr=None, def create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None,
loop=None, limit=streams._DEFAULT_LIMIT, **kwds): loop=None, limit=streams._DEFAULT_LIMIT, **kwds):
if loop is None: if loop is None:
loop = events.get_event_loop() loop = events.get_event_loop()
@ -188,7 +188,8 @@ def create_subprocess_exec(*args, stdin=None, stdout=None, stderr=None,
loop=loop) loop=loop)
transport, protocol = yield from loop.subprocess_exec( transport, protocol = yield from loop.subprocess_exec(
protocol_factory, protocol_factory,
*args, stdin=stdin, stdout=stdout, program, *args,
stdin=stdin, stdout=stdout,
stderr=stderr, **kwds) stderr=stderr, **kwds)
yield from protocol.waiter yield from protocol.waiter
return Process(transport, protocol, loop) return Process(transport, protocol, loop)

View File

@ -3,6 +3,7 @@
import errno import errno
import logging import logging
import socket import socket
import sys
import time import time
import unittest import unittest
import unittest.mock import unittest.mock
@ -234,8 +235,57 @@ class BaseEventLoopTests(unittest.TestCase):
self.assertEqual([handle], list(self.loop._ready)) self.assertEqual([handle], list(self.loop._ready))
def test_run_until_complete_type_error(self): def test_run_until_complete_type_error(self):
self.assertRaises( self.assertRaises(TypeError,
TypeError, self.loop.run_until_complete, 'blah') self.loop.run_until_complete, 'blah')
def test_subprocess_exec_invalid_args(self):
args = [sys.executable, '-c', 'pass']
# missing program parameter (empty args)
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_exec,
asyncio.SubprocessProtocol)
# exepected multiple arguments, not a list
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_exec,
asyncio.SubprocessProtocol, args)
# program arguments must be strings, not int
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_exec,
asyncio.SubprocessProtocol, sys.executable, 123)
# universal_newlines, shell, bufsize must not be set
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_exec,
asyncio.SubprocessProtocol, *args, universal_newlines=True)
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_exec,
asyncio.SubprocessProtocol, *args, shell=True)
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_exec,
asyncio.SubprocessProtocol, *args, bufsize=4096)
def test_subprocess_shell_invalid_args(self):
# exepected a string, not an int or a list
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_shell,
asyncio.SubprocessProtocol, 123)
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_shell,
asyncio.SubprocessProtocol, [sys.executable, '-c', 'pass'])
# universal_newlines, shell, bufsize must not be set
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_shell,
asyncio.SubprocessProtocol, 'exit 0', universal_newlines=True)
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_shell,
asyncio.SubprocessProtocol, 'exit 0', shell=True)
self.assertRaises(TypeError,
self.loop.run_until_complete, self.loop.subprocess_shell,
asyncio.SubprocessProtocol, 'exit 0', bufsize=4096)
class MyProto(asyncio.Protocol): class MyProto(asyncio.Protocol):