[Patches] [ python-Patches-511380 ] add CGIHTTPServer error supt for Win32
noreply@sourceforge.net
noreply@sourceforge.net
Thu, 31 Jan 2002 17:04:21 -0800
Patches item #511380, was opened at 2002-01-31 11:53
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=305470&aid=511380&group_id=5470
Category: Library (Lib)
Group: Python 2.3
Status: Open
Resolution: None
>Priority: 3
Submitted By: Wesley J. Chun (wesc)
Assigned to: Nobody/Anonymous (nobody)
Summary: add CGIHTTPServer error supt for Win32
Initial Comment:
Patch suggestion for CGIHTTPServer.py in the Python
Standard Library:
"add CGIHTTPServer error supt for Win32"
by Wesley J. Chun (wesc@rocketmail.com)
Python 2.2: Win32 and Unix (Solaris 2.8)
Description
===========
The CGIHTTPServer module uses the fork() mechanism
provided by Unix
to run the CGI script, however, since the Win32
platform does not
support fork(), CGIHTTPServer relies on os.popen2() to
execute the
process and to retrieve the results.
This all works however, when you are debugging CGI
applications, the
information provided by os.popen2() does not suffice
because execution
errors (i.e., Python tracebacks) are sent to standard
error, which are
ignored by os.popen2().
The suggested patch is to check first if os.popen3()
is available to
us (otherwise do the normal check for os.popen2()).
If we have access
to os.popen3(), use it instead and log any errors
which appear via the
child's stderr.
Without the patch, it makes it much more difficult to
debug the same
CGI application when run on Win32 because no errors
are made apparent
in the error log. Examples below -- first a
successful call is made
(200), followed by a failed call due to a Python
error, resulting in a
500 (ISE) appearing back on the web client.
The patch would bring the Win32 execution of
CGIHTTPServer much closer
to its Unix counterpart. A 3-line diff of the changes
is available just
below the examples. (This patch is valid for all 2.x
releases and may
be backported to the 2.[012].x releases if necessary.)
Unix
====
** NO PATCH NEEDED **
# cgihttpd.py # from CGIHTTPServer
import test; test()
Serving HTTP on port 8000 ...
localhost - - [30/Jan/2002 10:13:20] "GET /cgi-
bin/rwrl.py?admin=1 HTTP/1.0" 200 -
Traceback (most recent call last):
File "/home/wesc/public_html/cgi-bin/rwrl.py", line
177, in ?
main()
File "/home/wesc/public_html/cgi-bin/rwrl.py", line
153, in main
cd = tag % ('date', title, 'date')
UnboundLocalError: local variable 'title' referenced
before assignment
localhost - - [30/Jan/2002 10:13:20] CGI script exit
status 0x100
Windoze
=======
** BEFORE PATCH **
C:\dev>python cgihttpd.py
Serving HTTP on 0.0.0.0 port 8000 ...
solo - - [30/Jan/2002 21:37:27] "GET /cgi-bin/rwrl.py?
admin=-1 HTTP/1.1" 200 -
solo - - [30/Jan/2002 21:37:27] command: c:\python22
\python.exe -u C:\dev\cgi-bin\rwrl.py
solo - - [30/Jan/2002 21:37:28] CGI script exit status
0x1
** AFTER PATCH **
C:\dev>python cgihttpd.py
Serving HTTP on 0.0.0.0 port 8000 ...
solo - - [30/Jan/2002 21:46:22] "GET /cgi-bin/rwrl.py?
admin=-1 HTTP/1.1" 200 -
solo - - [30/Jan/2002 21:46:22] command: c:\python22
\python.exe -u C:\dev\cgi-bin\rwrl.py
solo - - [30/Jan/2002 21:46:23] Traceback (most recent
call last):
File "C:\dev\cgi-bin\rwrl.py", line 178, in ?
main()
File "C:\dev\cgi-bin\rwrl.py", line 160, in main
cd = tag % ('date', title, 'date')
UnboundLocalError: local variable 'title' referenced
before assignment
solo - - [30/Jan/2002 21:46:23] CGI script exit status
0x1
DIFF -C3
========
% diff -C3 CGIHTTPServer.py.CVS CGIHTTPServer.py.new
*** CGIHTTPServer.py.CVS Fri Oct 26 03:38:14
2001 UTC
--- CGIHTTPServer.py.new Thu Jan 31 10:58:16
2002 PST
***************
*** 41,46 ****
--- 41,47 ----
# Determine platform specifics
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
# the rest to a subprocess, so we can't use
buffered input.
***************
*** 123,129 ****
return
ispy = self.is_python(scriptname)
if not ispy:
! if not (self.have_fork or
self.have_popen2):
self.send_error(403, "CGI script is
not a Python script (%s)" %
`scriptname`)
return
--- 124,130 ----
return
ispy = self.is_python(scriptname)
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 (%s)" %
`scriptname`)
return
***************
*** 214,222 ****
self.server.handle_error
(self.request, self.client_address)
os._exit(127)
! elif self.have_popen2:
! # Windows -- use popen2 to create a
subprocess
import shutil
os.environ.update(env)
cmdline = scriptfile
if self.is_python(scriptfile):
--- 215,227 ----
self.server.handle_error
(self.request, self.client_address)
os._exit(127)
! elif self.have_popen3 or self.have_popen2:
! # Windows -- use popen2 or popen3 to
create a subprocess
import shutil
+ if self.have_popen3:
+ cmd = os.popen3
+ else:
+ cmd = os.popen2
os.environ.update(env)
cmdline = scriptfile
if self.is_python(scriptfile):
***************
*** 232,238 ****
nbytes = int(length)
except:
nbytes = 0
! fi, fo = os.popen2(cmdline, 'b')
if self.command.lower() == "post" and
nbytes > 0:
data = self.rfile.read(nbytes)
fi.write(data)
--- 237,247 ----
nbytes = int(length)
except:
nbytes = 0
! files = cmd(cmdline, 'b')
! fi = files[0]
! fo = files[1]
! if self.have_popen3:
! fe = files[2]
if self.command.lower() == "post" and
nbytes > 0:
data = self.rfile.read(nbytes)
fi.write(data)
***************
*** 239,244 ****
--- 248,258 ----
fi.close()
shutil.copyfileobj(fo, self.wfile)
+ if self.have_popen3:
+ anyerr = fe.read()
+ fe.close()
+ if anyerr:
+ self.log_error('%s', anyerr)
sts = fo.close()
if sts:
self.log_error("CGI script exit
status %#x", sts)
else:
----------------------------------------------------------------------
You can respond by visiting:
http://sourceforge.net/tracker/?func=detail&atid=305470&aid=511380&group_id=5470