2012-03-05 80 views
3

我试图做出Bugzilla的小测试服务器,所以我可以测试出我的变化使他们部署到基于Apache主服务器之前。我最熟悉Python,并且我想让Python的内置HTTP服务器运行Bugzilla的CGI程序。如何从WSGI处理程序启动CGI脚本?

不幸的是,Bugzilla的有很多比CGI应用程序更多。它有一堆直接提供的css和其他数据。这意味着处理程序也需要处理这些。我想设置一个WSGI处理程序,它查看请求URL并将请求适当地路由到任一Bugzilla CGI脚本或直接从文件系统中获取数据。

有没有更好的方式来完成我想做什么?如果没有,那么是否已经有一个WSGI应用程序可以建立一个CGI环境并通过Python的subprocess模块向CGI应用程序发出呼叫?

+1

这可能是一个容易得多,刚刚成立的httpd已经做了你所需要的一个小的配置文件。 – 2012-03-05 19:43:29

+0

@ IgnacioVazquez-Abrams - 我不明白那会怎么简单。阿帕奇一直像是一个非常痛苦的野兽去跑步。我所做过的所有网络应用都令人愉快,只有一个微型Web服务器可以用于开发。 – Omnifarious 2012-03-05 20:10:12

+0

如果配置Apache是​​问题,您可能需要尝试[xampp](http://www.apachefriends.org/en/xampp.html)。 – 2012-03-06 04:12:08

回答

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,) 
+0

这不是一个真正的答案,但它是唯一解决我的问题。如果我自己写网关,我会坚持下去。 – Omnifarious 2012-03-15 15:05:20

+0

我自己写了一个网关。 – Omnifarious 2012-03-26 21:02:36

1

是否使用pybugz? http://www.liquidx.net/pybugz/

http://code.google.com/p/pybugz/

此外,通过Django和AppEngine上设置WSGI是很容易的。很快安装,可能值得使用作为解决。这会让你应该能够处理Bugzilla的CGI,CSS等

好运

+0

还没有,但我不想重新编写整个Bugzilla UI,无论如何pybugz方面。我想要一个通用的WSGI-> CGI网关,因为各种不同的小型Python网络服务器都是面向WSGI服务的。我不想要一个可以使用WSGI和CGI的特定Python Web服务器。我想要一个网关,所以我选择了Web服务器。 – Omnifarious 2012-03-09 18:43:30