我正在尝试为Bugzilla创建一个小型测试服务器,以便在将它们部署到基于Apache的主服务器之前测试我所做的更改。我最熟悉Python,我想让Python的内置HTTP服务器运行Bugzilla的CGI程序。
不幸的是,Bugzilla拥有的不仅仅是CGI应用程序。它有一堆css和其他直接提供的数据。这意味着处理程序也需要处理这些。我想设置一个WSGI处理程序来查看请求URL,并将请求适当地路由到任何一个Bugzilla CGI脚本或直接从文件系统中提取数据。
有没有更好的方法来完成我想做的事情?如果没有,那么是否有一个WSGI应用程序已经设置了CGI环境并通过Python的subprocess
模块调用CGI应用程序?
答案 0 :(得分:5)
这是一个有效的解决方案,虽然它相当丑陋且有点慢。它需要为您要运行的每个CGI脚本单独的CGIApplication
对象。因此,如果您有一个完整的目录,则需要为每个目录实例化一个不同的CGIApplication
对象。当你实例化它时,当然取决于你。您可以选择为每个请求实例化新的请求,但如果您以某种方式避免这种情况,您可能会节省一些时间。
import os
import os.path as _osp
import re
import subprocess
import io
import email.parser
env_forward = re.compile('^[A-Z][A-Z0-9_]*$')
header_match = re.compile(b'^(.*?\\n[ \\t\\r]*\\n)(.*)$', re.M | re.S)
env_whitelist = frozenset(('AUTH_TYPE', 'CONTENT_LENGTH', 'CONTENT_TYPE',
'DOCUMENT_ROOT', 'QUERY_STRING', 'PATH_INFO',
'PATH_TRANSLATED', 'REMOTE_ADDR', 'REMOTE_PORT',
'REMOTE_IDENT', 'REMOTE_USER', 'REQUEST_METHOD',
'REQUEST_URI', 'SCRIPT_NAME',
'SERVER_ADDR', 'SERVER_ADMIN', 'SERVER_NAME',
'SERVER_PORT', 'SERVER_PROTOCOL',
'SERVER_SIGNATURE', 'SERVER_SOFTWARE'))
class CGIApplication(object):
def __init__(self, appfname):
self._appfname = _osp.abspath(appfname)
def __call__(self, environ, start_respose):
appenv = {item[0]: item[1] \
for item in environ.items() \
if ((item[0] in env_whitelist) or
item[0].startswith('HTTP_'))}
appenv['GATEWAY_INTERFACE'] = 'CGI/1.1'
appenv['PATH'] = '/usr/local/bin:/usr/bin:/bin'
appenv['SCRIPT_FILENAME'] = self._appfname
nbytes_for_cgi = appenv.get('CONTENT_LENGTH', '')
nbytes_for_cgi = (int(nbytes_for_cgi) if nbytes_for_cgi != '' else 0)
args = [self._appfname]
query = environ.get('QUERY_STRING', None)
query = query.replace('+', ' ')
if '=' not in query:
args.append(query)
proc = subprocess.Popen(args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env = appenv,
cwd = _osp.dirname(self._appfname))
bytes_read = 0
data_for_cgi = io.BytesIO()
while bytes_read < nbytes_for_cgi:
data = environ['wsgi.input'].read(nbytes_for_cgi - bytes_read)
bytes_read += len(data)
data_for_cgi.write(data)
data = None
data_for_cgi = data_for_cgi.getvalue()
output, errdata = proc.communicate(data_for_cgi)
data_for_cgi = None
proc.stdin.close()
proc.stdout.close()
proc.stderr.close()
try:
errdata = errdata.decode('utf-8')
except UnicodeDecodeError:
errdata = errdata.decode('iso8859-1')
environ['wsgi.errors'].write(errdata)
errdata = None
if proc.returncode != 0:
start_respose('500 Internal Server Error',
[('Content-Type', 'text/plain')])
return (b"CGI application died with non-zero return code.\n",)
else:
output_hdr = header_match.match(output)
output_hdr, output = output_hdr.groups()
parser = email.parser.HeaderParser()
headers = parser.parsestr(output_hdr.decode('iso8859-1'))
status = headers.get_all('Status', ['200 OK'])[-1]
del headers['Status']
start_respose(status, list(headers.items()))
return (output,)
答案 1 :(得分:1)
http://code.google.com/p/pybugz/
此外,通过Django和AppEngine设置WSGI非常简单。安装起来非常快,可能值得用作解决方法。那会让你成为一个应该能够处理bugzilla的cgi,css等的测试服务器。
祝你好运