Commit cb0d2d71 authored by Amaury Forgeot d'Arc's avatar Amaury Forgeot d'Arc

Issue3113: tests for CGIHTTPRequestHandler failed on windows:

replace the now-invalid popen2 with a call to subprocess.Popen.
parent 1afc1696
...@@ -13,9 +13,7 @@ Notes on CGIHTTPRequestHandler ...@@ -13,9 +13,7 @@ Notes on CGIHTTPRequestHandler
This class implements GET and POST requests to cgi-bin scripts. This class implements GET and POST requests to cgi-bin scripts.
If the os.fork() function is not present (e.g. on Windows), If the os.fork() function is not present (e.g. on Windows),
os.popen2() is used as a fallback, with slightly altered semantics; if subprocess.Popen() is used as a fallback, with slightly altered semantics.
that function is not present either (e.g. on Macintosh), only Python
scripts are supported, and they are executed by the current process.
In all cases, the implementation is intentionally naive -- all In all cases, the implementation is intentionally naive -- all
requests are executed synchronously. requests are executed synchronously.
...@@ -826,8 +824,6 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler): ...@@ -826,8 +824,6 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
# Determine platform specifics # Determine platform specifics
have_fork = hasattr(os, 'fork') have_fork = hasattr(os, 'fork')
have_popen2 = hasattr(os, 'popen2')
have_popen3 = hasattr(os, 'popen3')
# Make rfile unbuffered -- we need to read one line and then pass # Make rfile unbuffered -- we need to read one line and then pass
# the rest to a subprocess, so we can't use buffered input. # the rest to a subprocess, so we can't use buffered input.
...@@ -929,10 +925,6 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler): ...@@ -929,10 +925,6 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
return return
ispy = self.is_python(scriptname) ispy = self.is_python(scriptname)
if not ispy: if not ispy:
if not (self.have_fork or self.have_popen2 or self.have_popen3):
self.send_error(403, "CGI script is not a Python script (%r)" %
scriptname)
return
if not self.is_executable(scriptfile): if not self.is_executable(scriptfile):
self.send_error(403, "CGI script is not executable (%r)" % self.send_error(403, "CGI script is not executable (%r)" %
scriptname) scriptname)
...@@ -1041,13 +1033,9 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler): ...@@ -1041,13 +1033,9 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
self.server.handle_error(self.request, self.client_address) self.server.handle_error(self.request, self.client_address)
os._exit(127) os._exit(127)
elif self.have_popen2 or self.have_popen3:
# Windows -- use popen2 or popen3 to create a subprocess
import shutil
if self.have_popen3:
popenx = os.popen3
else: else:
popenx = os.popen2 # Non-Unix -- use subprocess
import subprocess
cmdline = scriptfile cmdline = scriptfile
if self.is_python(scriptfile): if self.is_python(scriptfile):
interp = sys.executable interp = sys.executable
...@@ -1062,54 +1050,26 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler): ...@@ -1062,54 +1050,26 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
nbytes = int(length) nbytes = int(length)
except (TypeError, ValueError): except (TypeError, ValueError):
nbytes = 0 nbytes = 0
files = popenx(cmdline, 'b') p = subprocess.Popen(cmdline,
fi = files[0] stdin=subprocess.PIPE,
fo = files[1] stdout=subprocess.PIPE,
if self.have_popen3: stderr=subprocess.PIPE,
fe = files[2] )
if self.command.lower() == "post" and nbytes > 0: if self.command.lower() == "post" and nbytes > 0:
data = self.rfile.read(nbytes) data = self.rfile.read(nbytes)
fi.write(data) else:
data = None
# throw away additional data [see bug #427345] # throw away additional data [see bug #427345]
while select.select([self.rfile._sock], [], [], 0)[0]: while select.select([self.rfile._sock], [], [], 0)[0]:
if not self.rfile._sock.recv(1): if not self.rfile._sock.recv(1):
break break
fi.close() stdout, stderr = p.communicate(data)
shutil.copyfileobj(fo, self.wfile) self.wfile.write(stdout)
if self.have_popen3: if stderr:
errors = fe.read() self.log_error('%s', stderr)
fe.close() status = p.returncode
if errors: if status:
self.log_error('%s', errors) self.log_error("CGI script exit status %#x", status)
sts = fo.close()
if sts:
self.log_error("CGI script exit status %#x", sts)
else:
self.log_message("CGI script exited OK")
else:
# Other O.S. -- execute script in this process
save_argv = sys.argv
save_stdin = sys.stdin
save_stdout = sys.stdout
save_stderr = sys.stderr
try:
save_cwd = os.getcwd()
try:
sys.argv = [scriptfile]
if '=' not in decoded_query:
sys.argv.append(decoded_query)
sys.stdout = self.wfile
sys.stdin = self.rfile
exec(open(scriptfile).read(), {"__name__": "__main__"})
finally:
sys.argv = save_argv
sys.stdin = save_stdin
sys.stdout = save_stdout
sys.stderr = save_stderr
os.chdir(save_cwd)
except SystemExit as sts:
self.log_error("CGI script exit status %s", str(sts))
else: else:
self.log_message("CGI script exited OK") self.log_message("CGI script exited OK")
......
...@@ -81,6 +81,8 @@ Extension Modules ...@@ -81,6 +81,8 @@ Extension Modules
Library Library
------- -------
- Patch #3133: http.server.CGIHTTPRequestHandler did not work on windows.
- a new ``urllib`` package was created. It consists of code from - a new ``urllib`` package was created. It consists of code from
``urllib``, ``urllib2``, ``urlparse``, and ``robotparser``. The old ``urllib``, ``urllib2``, ``urlparse``, and ``robotparser``. The old
modules have all been removed. The new package has five submodules: modules have all been removed. The new package has five submodules:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment